1.ORM技术简介
ORM:Object-Relational Mapping,把关系数据库的表结构映射到对象上。
数据库表是一个二维表,包含多行多列。把一个表的内容用Python的数据结构表示出来的话,可以用一个list表示多行,list的每一个元素是tuple,表示一行记录,比如,包含id和name的user表
[
('1', 'Michael'),
('2', 'Bob'),
('3', 'Adam')
]
Python的DB-API返回的数据结构就是像上面这样表示的, 但是用tuple表示一行很难看出表的结构。如果把一个tuple用class实例来表示,就可以更容易地看出表的结构来:
class User(object):
def __init__(self, id, name):
self.id = id
self.name = name
[
User('1', 'Michael'),
User('2', 'Bob'),
User('3', 'Adam')
]
2.SQLAlchemy的使用
上述就是ORM技术 ,把关系数据库的表结构映射到对象上。但是由谁来做这个转换呢?所以ORM框架应运而生。 在Python中,最有名的ORM框架是SQLAlchemy。我们来看看SQLAlchemy的用法。 首先通过pip安装SQLAlchemy:
$ pip install sqlalchemy
初始化连接:
$ from sqlalchemy import create_engine #导入
$ engine = create_engine('mysql+pymsql://user:passwd@serverip/dbname', echo=True)
echo参数为True时,会显示每条执行的SQL语句,可以不写即为关闭。
create_engine()返回一个Engine的实例,并且它表示通过数据库语法处理细节的核心接口,在这种情况下,数据库语法将会被解释成python的类方法。
mysql: 指定是哪种数据库连接,+pymsql 使用该包进行连接,默认为mysqldb。
user: 连接的用户名
passwd:连接用户对应的密码
serverIP: 数据库的ip
dbname: 需要连接库的名字
1).创建数据表
(1)主要是通过sql语句来创建表格:
from sqlalchemy import create_engine # 导入:
engine = create_engine('mysql+pymysql://xiang:xiang@192.168.48.136/sqlalchemy') #创建连接
#建表语句
sql = '''create table student(
id int not null PRIMARY KEY,
name varchar(100),
age int,
address varchar(100)
);'''
cus = engine.connect() #获取连接
cus.execute(sql) #创建
cus.close() #关闭
engine.connect() 表示获取到数据库连接。类似我们在pymysql中游标course的作用。
(2)通过ORM的方式创建表
# 导入
from sqlalchemy import create_engine, MetaData, Column, Integer, String, Table
# 初始化数据库连接(echo=True打印操作信息):
engine = create_engine("mysql+pymysql://user:passwd@IP/test")
# 创建users表
metadata = MetaData(engine)
users = Table('users',metadata,
Column('id',Integer,primary_key=True),
Column('name',String(10)),
Column('password',Integer),
Column('email',Integer,unique=True),
Column('score',Integer)
)
#如果要创建多个表继续写就行了
#user2 = Table('user2',metadata,
Column(...)
)
# 创建表
metadata.create_all(engine)
运行之后users表就创建好了:
mysql> desc users;
+----------+-------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------+-------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| name | varchar(10) | YES | | NULL | |
| password | int(11) | YES | | NULL | |
| email | int(11) | YES | UNI | NULL | |
| score | int(11) | YES | | NULL | |
+----------+-------------+------+-----+---------+----------------+
5 rows in set (0.00 sec)MetaData类主要用于保存表结构,连接字符串等数据,是一个多表共享的对象
metadata = MetaData(engine) 绑定一个数据源的metadata
metadata.create_all(engine)
是来创建表,这个操作是安全的操作,会先判断表是否存在。
Table类 构造函数:
Table.__init__(self, name, metadata,*args, **kwargs)
name 表名
metadata 共享的元数据
*args Column 是列定义
可变参数 **kwargs 定义:
schema 此表的结构名称,默认None
autoload 自动从现有表中读入表结构,默认False
autoload_with 从其他engine读取结构,默认None
include_columns 如果autoload设置为True,则此项数组中的列明将被引用,没有写的列明将被忽略,None表示所有都列明都引用,默认None
mustexist 如果为True,表示这个表必须在其他的python应用中定义,必须是metadata的一部分,默认False
useexisting 如果为True,表示这个表必须被其他应用定义过,将忽略结构定义,默认False
owner 表所有者,用于Orcal,默认None
quote 设置为True,如果表明是SQL关键字,将强制转义,默认False
quote_schema 设置为True,如果列明是SQL关键字,将强制转义,默认False
mysql_engine mysql专用,可以设置'InnoDB'或'MyISAM'Column类 构造函数:
Column.__init__(self, name, type_, *args, **kwargs)
1、name 列名
2、type_ 类型,更多类型 sqlalchemy.types
3、*args Constraint(约束), ForeignKey(外键), ColumnDefault(默认), Sequenceobjects(序列)定义
4、key 列名的别名,默认None
下面是可变参数 **kwargs
5、primary_key 如果为True,则是主键
6、nullable 是否可为Null,默认是True
7、default 默认值,默认是None
8、index 是否是索引,默认是True
9、unique 是否唯一键,默认是False
10、onupdate 指定一个更新时候的值,这个操作是定义在SQLAlchemy中,不是在数据库里的,当更新一条数据时设置,大部分用于updateTime这类字段
11、autoincrement 设置为整型自动增长,只有没有默认值,并且是Integer类型,默认是True
12、quote 如果列明是关键字,则强制转义,默认False
2.创建会话,并对数据进行增删改查操作
说到数据库,就离不开Session。Session的主要目的是建立与数据库的会话,它维护你加载和关联的所有数据库对象。它是数据库查询(Query)的一个入口。
在Sqlalchemy中,数据库的查询操作是通过Query对象来实现的。而Session提供了创建Query对象的接口。
Query对象返回的结果是一组同一映射(Identity Map)对象组成的集合。事实上,集合中的一个对象,对应于数据库表中的一行(即一条记录)。所谓同一映射,是指每个对象有一个唯一的ID。如果两个对象(的引用)ID相同,则认为它们对应的是相同的对象。
要完成数据库查询,就需要建立与数据库的连接。这就需要用到Engine对象。一个Engine可能是关联一个Session对象,也可能关联一个数据库表。
当然Session最重要的功能还是实现原子操作。
ORM通过session与数据库建立连接进行通信,如下所示:
# 导入:
from sqlalchemy.orm import sessionmaker
DBSession = sessionmaker(bind=engine)
session = DBSession()
通过sessionmake方法创建一个Session工厂,然后在调用工厂的方法来实例化一个Session对象。
增加数据
# 导入
from sqlalchemy import create_engine, MetaData, Column, Integer, String, Table
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker
# 初始化数据库连接
engine = create_engine("mysql+pymysql://user:passwd@IP/test")
# 创建DBSession类型:
DBsession = sessionmaker(bind=engine)
session = DBsession()
# 创建对象的基类:
Base = declarative_base()
class User(Base):
# 表的名字:
__tablename__ = 'users'
# 表的结构:
id = Column(Integer(), primary_key=True)
name = Column(String(10))
password=Column(Integer())
email=Column(Integer(),unique=True)
score=Column(Integer())
# 添加数据
u1=User(name='a',password=1,email=1,score=12)
u2=User(name='b',password=2,email=2,score=15)
u3=User(name='c',password=3,email=3,score=21)
session.add_all([u1,u2,u3])
session.commit()
session.close()
这样数据就添加上了:
mysql> select * from users;
+----+------+----------+-------+-------+
| id | name | password | email | score |
+----+------+----------+-------+-------+
| 1 | a | 1 | 1 | 12 |
| 2 | b | 2 | 2 | 15 |
| 3 | c | 3 | 3 | 21 |
+----+------+----------+-------+-------+
3 rows in set (0.00 sec)
查询数据
filter(User.id==1001) 这个就必须使用User.id ,可以使用> < ==等
#查询数据
user=session.query(User).filter(User.id==1).one()
print('type:',type(user))
print('name:',user.name)
将添加例子中的添加数据操作替换为查询即可,运行结果:
type: <class '__main__.User'>
name: a
可见,ORM就是把数据库表的行与相应的对象建立关联,互相转换。
上述的命令中one()表示一个,也可是使用all()表示多个:
user=session.query(User).filter(User.id>1).all()
print(user)
for i in user:
print(i.id,i.name)
运行结果为:
[<__main__.User object at 0x0000029AB569A2B0>, <__main__.User object at 0x0000029AB569A320>]
2 b
3 c
filter_by(id=1) 不能使用> < ==
user=session.query(User).filter_by(id=1).one()
print(user.id,user.name)
运行结果为:
1 a
修改数据
#修改数据:获取一条数据对象,修改属性并提交即可
user=session.query(User).filter(User.id==1).one()
user.score=99
session.commit()
session.close()
我们查一下看是否改变:
mysql> select * from users;
+----+------+----------+-------+-------+
| id | name | password | email | score |
+----+------+----------+-------+-------+
| 1 | a | 1 | 1 | 99 |
| 2 | b | 2 | 2 | 15 |
| 3 | c | 3 | 3 | 21 |
+----+------+----------+-------+-------+
3 rows in set (0.00 sec)
可见已经改变。
删除数据
#删除用户
u=session.query(User).filter(User.id==2).one()
session.delete(u)
session.commit()
提交查看结果:
mysql> select * from users;
+----+------+----------+-------+-------+
| id | name | password | email | score |
+----+------+----------+-------+-------+
| 1 | a | 1 | 1 | 99 |
| 3 | c | 3 | 3 | 21 |
+----+------+----------+-------+-------+2 rows in set (0.00 sec)
可见id为2的数据已经没有了。