概念简介
- ORM
ORM
是Object-Relational Mapping的简写。今天学习的SQLAlchemy
其实就是ORM框架中最有名的一个。SQLAlchemy
框架工作
通过数据的API,使用关系对象映射进行数据库操作,也就是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
SQLAlchemy本身无法操作数据库,其必须通过pymysql
等第三方插件。上图中Dialect用于和数据API进行交流,根据配置文件的不同调用不同的数据库API,从而实现对数据库的操作。1
2
3
4
5
6
7
8# mysqldb
mysql+mysqldb://<user>:<password>@<host>[:<port>]/<dbname>
# pymysql
mysql+pymysql://<username>:<password>@<host>/<dbname>[?<options>]
# mysql-connector
mysql+mysqlconnector://<user>:<password>@<host>[:<port>]/<dbname>
# cx_oracle
oracle+cx_oracle://user:pass@host:port/dbname[?key=value&key=value...]
对比
ORM思想的核心是隐藏了数据访问细节,提供了通用的数据库交互。并且完全不用考虑SQL语句,从而快速开发。
- 使用SQL创建表
1
2
3
4
5
6
7CREATE TABLE student(
id int not null auto_increment,
name varchar(100),
age int,
address varchar(100),
PRIMARY KEY(id)
)
上述是一个简单的创建单表的语句。
- 使用SQLAlchemy
方法11
2
3
4
5
6
7
8
9
10
11
12
13
14
15from sqlalchemy import create_engine, Column, String, Integer, MetaData
from sqlalchemy.ext.declarative import declarative_base
engine = create_engine("mysql+pymysql://root:123456@localhost/test", encoding='UTF-8', echo=True)
Base = declarative_base() #生成orm基类
class Student(Base):
__tablename__ = 'student' #指定表名
id = Column(Integer, primary_key=True)
name = Column(String(100))
age = Column(Integer)
address = Column(String(100))
Base.metadata.create_all(engine) #创建表结构
方法21
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22from sqlalchemy import Table, MetaData, Column, Integer, String, create_engine
from sqlalchemy.orm import mapper
engine = create_engine("mysql+pymysql://root:123456@localhost/test", encoding='UTF-8', echo=True)
metadata = MetaData()
student = Table('student', metadata,
Column('id', Integer, primary_key=True),
Column('name', String(100)),
Column('age', Integer),
Column('address', String(100))
)
class Student(object):
def __init__(self, name, age, address):
self.name = name
self.age = age
self.address = address
mapper(Student, student) #此处有问题,待解决
说明echo=True
显示每条执行的SQL语句,可以关闭。create_engine()
返回一个Engine的实例,并且表示通过数据库语法处理细节的核心接口,这种情况下数据库语法将被解释成python的类方法。
上面简单示例对比了下使用SQL直接创建表和使用ORM框架建表的区别,下面开始介绍SQLAlchemy
的使用。
使用
安装
通过pip install SQLAlchemy
安装,访问mysql使用pymysql
,安装方法pip install pumysql
。可以参照python访问mysql。
插入
1 | from sqlalchemy import create_engine, Column, String, Integer, MetaData |
查询
查询是通过Session的query()
方法创建一个查询对象,这个函数的参数可以是任何类或者类的描述的集合。
查询出来的数据是一个对象,直接通过对象的属性调用。1
2
3
4
5
6
7
8
9
10
11
12from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from db.orm2 import Student
engine = create_engine('mysql+pymysql://root:123456@localhost/test')
DBsession = sessionmaker(bind=engine)
session = DBsession()
a = session.query(Student)
print(a)
for i in a:
print(i.id, i.name, i.age, i.address)
输出结果1
2
3
4
5SELECT student.id AS student_id, student.name AS student_name, student.age AS student_age, student.address AS student_address
FROM student
1001 Alice 25 anhui
1002 Bob 69 beijing
1003 Cerry 14 jiangsu
session.query(Student)
结果为查询的SQL语句,若出现查询结果错误可以通过查看SQL确认。
- filter()和filter_by()
过滤条件。==
、!=
、like
等过滤操作都可以在filter函数中使用。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from db.orm2 import Student
engine = create_engine('mysql+pymysql://root:123456@localhost/test')
DBsession = sessionmaker(bind=engine)
session = DBsession()
a = session.query(Student).filter(Student.id == 1001)
b = session.query(Student).filter_by(id=1001)
for x in a:
print(x.id, x.name, x.age, x.address)
for i in b:
print(i.id, i.name, i.age, i.address)
输出结果1
21001 Alice 25 anhui
1001 Alice 25 anhui
filter()
和filter_by()
区别
filter可以像写sql的where条件那样写>、<等条件,但引用列名时,需要通过类名.属性名
的方式。
filter_by可以使用python的正常参数传递方法传递条件,指定列名时,不需要额外指定类名,参数名对应类中的属性名,不能使用>、<等条件。
当使用filter的时候条件之间是使用==
,filter_by使用的是=
。
filter不支持组合查询,只能连续调用filter变相实现。filter_by的参数是**kwargs,直接支持组合查询。1
2
3
4filters = {'id':1002, 'name':'Bob'}
b = session.query(Student).filter_by(**filters)
for i in b:
print(i.id, i.name, i.age, i.address)
输出结果1
1002 Bob 69 beijing
- all()
返回一个列表,可以通过遍历列表获取每个对象。1
2
3
4a = session.query(Student).filter(Student.id > 1001).all()
print(a)
for x in a:
print(x.id, x.name, x.age, x.address)
输出结果1
2
3[<db.orm2.Student object at 0x00000197ECC759E8>, <db.orm2.Student object at 0x00000197ECC75A58>]
1002 Bob 69 beijing
1003 Cerry 14 jiangsu
- one()
返回且仅返回一个查询结果。当结果数量不足或者多于一个时会报错。1
2
3a = session.query(Student).filter(Student.id == 1001).one()
print(a)
print(a.id, a.name, a.age, a.address)
输出结果1
2<db.orm2.Student object at 0x000001B7C57E7908>
1001 Alice 25 anhui
- first()
返回至多一个结果,而且以单项形式,而不是只有一个元素的tuple形式返回。1
2
3a = session.query(Student).filter(Student.id > 1001).first()
print(a)
print(a.id, a.name, a.age, a.address)
输出结果1
2<db.orm2.Student object at 0x000001C63E536B00>
1002 Bob 69 beijing
说明
- 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)
name 列名
type_ 类型,更多类型sqlalchemy.types
下面是*args
参数定义
Constraint(约束)
ForeignKey(外键)
ColumnDefault(默认)
Sequenceobjects(序列)定义
key 列名的别名,默认None
下面是**kwargs
参数定义
primary_key 如果为True,则是主键
nullable 是否可为Null,默认是True
default 默认值,默认是None
index 是否是索引,默认是True
unique 是否唯一键,默认是False
onupdate 指定一个更新时候的值,这个操作是定义在SQLAlchemy中,不是在数据库里的,当更新一条数据时设置,大部分用于updateTime这类字段
autoincrement 设置为整型自动增长,只有没有默认值,并且是Integer类型,默认是True
quote 如果列明是关键字,则强制转义,默认False - 创建会话
Session的主要目的是建立与数据库的会话,它维护你加载和关联的所有数据库对象。它是数据库查询(Query)的一个入口。
在SQLAlchemy
中,数据库的查询操作是通过Query对象来实现的,而Session提供了创建Query对象的接口。Query对象返回的结果是一组同一映射(Identity Map)对象组成的集合。事实上,集合中的一个对象,对应于数据库表中的一行(即一条记录)。所谓同一映射,是指每个对象有一个唯一的ID。如果两个对象(的引用)ID相同,则认为它们对应的是相同的对象。
要完成数据库查询,就需要建立与数据库的连接。这就需要用到Engine对象。一个Engine可能是关联一个Session对象,也可能关联一个数据库表。
当然Session最重要的功能还是实现原子操作。
ORM通过session与数据库建立连接进行通信,如下所示1
2
3
4from sqlalchemy.orm import sessionmaker
DBSession = sessionmaker(bind=engine)
session = DBSession()
通过sessionmake方法创建一个Session工厂,然后在调用工厂的方法来实例化一个Session对象。
要了解更多关于SQLAlchemy
内容可以点击SQLAlchemy Documentation查看官方介绍。