SQLAlchemy是Python编程语言下的一款ORM框架,该框架建立在数据库API之上,使用关系对象映射进行数据库操作,简言之便是:将对象转换成SQL,然后使用数据API执行SQL并获取执行结果。
ORM全称是:Object Relational Mapping(对象关系映射),其主要作用是在编程中,把面向对象的概念跟数据库中表的概念对应起来。举例来说就是,定义一个对象,那就对应着一张表,这个对象的实例,就对应着表中的一条记录。
类 –> 表
类的属性 –> 表中的字段
类的实例 –> 表中一条记录
ORM 有下面这些优点。
- 数据模型都在一个地方定义,更容易更新和维护,也利于重用代码。
- ORM 有现成的工具,很多功能都可以自动完成,比如数据消毒、预处理、事务等等。
- 它迫使你使用 MVC 架构,ORM 就是天然的 Model,最终使代码更清晰。
- 基于 ORM 的业务代码比较简单,代码量少,语义性好,容易理解。
- 你不必编写性能不佳的 SQL。
引擎和声明基类
使用SQLAlchemy连接数据库需要引擎,创建引擎使用create_engine
方法:
1 | from sqlalchemy import create_engine |
创建映射类需要继承声明基类,使用declarative_base:
1 | from sqlalchemy.ext.declarative import declarative_base |
创建映射类
创建映射类须继承声明的基类。
1 | # Column 定义字段,Integer、String 分别为整数和字符串数据类型 |
一对多关系
1 | from sqlalchemy import ForeignKey |
定义列时常用的参数:
参数 | 说明 |
---|---|
primary_key | 如果设为True,这列就是表的主键 |
unique | 默认值为False,如果为True,表示这列不允许重复 |
index | 如果为True,为这列创建索引 |
nullable | 默认为True,这列允许使用空值 |
defaule | 为这列设置默认值 |
创建数据表
声明基类 Base 在创建之后并不会主动连接数据库,因为它的默认设置为惰性模式。Base 的 metadata 有个 create_all 方法,执行此方法会主动连接数据库并创建全部数据表,完成之后自动断开与数据库的连接:Base.metadata.create_all()
Session处理数据
使用映射类创建数据表要用声明基类Base,而处理数据要用到session。它是sessionmaker类的实例,该实例实现了__call__方法,本身可以作为函数来执行,返回值就是能够处理数据的session。
1 | from sqlalchemy.orm import sessionmaker |
当我们创建了 session 实例,就启动了一个操作 MySQL 数据库的会话。
session对象常用的操作方法:
方法 | 描述 |
---|---|
add(self, instance, __warn=True) | 向数据库保存一个实体对象 |
add_all(self, instance) | 向数据库保存一组实体 |
merge(self, instance, load=True) | 合并数据实体(更新) |
query(self, *entities, **kwargs) | 数据查询 |
delete(self, instance) | 删除指定的数据实体 |
commit(self) | 事物提交 |
rollback(self) | 事物回滚 |
数据查询
基本查询
session 的 query 方法接收类作为参数,.all
表示获取全部实例
不论查询结果是一个还是多个,返回值都是列表,查不到的话返回值是空列表。等同于 MySQL 语句:SELECT *
1 | # 获取全部实例 |
like
方法进行模糊查询,%
匹配任意数量的任意字符,_
匹配单个任意字符。
1 | # 查询邮箱为谷歌邮箱的 User 实例 |
in_
方法查询”某个字符安的值属于某个列表中”的数据
1 | # 如果列表中的字段在 name 列中查不到,并不会报错 |
and_
方法进行多条件查询,需要引入,等同于filter_by方法
1 | from sqlalichemy import and_ |
or_
也是多条件查询,符合任一条件即可,也是需要引入。
1 | from sqlalchemy import or_ |
高级查询
排序
使用order_by
方法根据某一字段进行排序
1 | session.query(User).order_by(User.name).all() |
设置查询数量(分页查询)
使用limit
方法限制查询数量
1 | session.query(User).limit(4).all() |
count
方法统计查询数量
1 | session.query(User).count() |
多表联结查询
使用join
方法进行联结查询
1 | # 查询user1的全部课程,即查询course表中的数据 |
添加数据
1 | user = Users(username="user3", email="user3@qq.com") # 实例化数据映射类作为表的一行数据 |
更新数据
1 | user = Users(id=4, username="user4", email="user4@qq.com") # 实例化数据映射类作为表的一行数据 |
删除数据
1 | session.query(User).filter(User.id == 1).delete() |
执行原生sql
connection方式
使用传统的connection的方式连接和操作数据库
1 | from sqlalchemy import create_engine |
在connection方式下,传递sql语句参数的参数形式与传统方式相同,使用?
占位,元组形式传参,但前提是下层的 DBAPI 支持。更好的方式是使用 text()
。
1 | con.execute("insert into user (name,password) values (?,?)",('admin','password')) |
使用text构建SQL
相比直接使用 string,text() 的优势在于它:提供了统一的参数绑定语法,与具体的 DBAPI 无关。
参数绑定语法
1
2
3
4from sqlalchemy import text
# 使用dict 传参数
result = con.execute(text("select * from table where id = :id"), {"id":1})参数类型指定
1
2
3
4
5
6
7
8
9
10from sqlalchemy import text
from sqlalchemy import DateTime
date_param = datetime.today()+timedelta(days=-1*10)
sql="delete from caw_job_alarm_log where alarm_time < :alarm_time_param"
# bindparams 是 bindparam 的列表,bindparam 则提供参数的一些额外信息(类型、值、限制等)
t=text(sql, bindparams=[bindparam('alarm_time_param', type_=DateTime, required=True)])
connection.execute(t, {"alarm_time_param": date_param})
connection事务方式
使用事务可以进行批量提交和回滚
1 | with engine.connect() as con: |
session方式
connection是一般使用数据库的方式,sqlalchemy还提供了另一种操作数据库的方式,通过session对象,session可以记录和跟踪数据的改变,在适当的时候提交,并且支持强大的ORM的功能
1 | from sqlalchemy.orm import sessionmaker |
注意:参数使用dict,并在sql语句中使用:key
占位