官方文档:https://docs.sqlalchemy.org/
SQLAlchemy是一个Python的SQL工具和ORM 框架,提供了丰富的SQL操作和数据持久化功能,支持多种数据库,包括 PostgreSQL、MySQL、Oracle、SQLite 等。SQLAlchemy分为SQL Expression Language和ORM两部分。
优点:
缺点:
字段 | 说明 | 可选属性 |
---|---|---|
Integer | 整型 | primary_key autoincrement |
String | 字符串 | |
Text | 文本 | |
Float | 浮点型 | 精度precision 小数位数scale |
DateTime | 日期时间 | |
Boolean | 布尔型 | |
Enum | 枚举 | choices |
JSON | JSON 数据类型 | |
ARRAY | 数组数据类型 | |
BigInteger | 大整型 | |
Interval | 时间间隔,用于存储时间差值 | |
ForeignKey | 外键 | 删除时的行为ondelete 更新时的行为onupdate |
Relationship | 关系 | 反向引用backref |
Column | 列 | 是否唯一unique 是否索引index |
选项 | 说明 | 备注 |
---|---|---|
nullable | 是否可为空 | |
default | 默认值 | |
primary_key | 是否为主键 | |
unique | 是否唯一 | |
index | 是否为索引 | |
autoincrement | 是否自动递增 | |
ondelete | 删除时的行为 | |
onupdate | 更新时的行为 | |
server_default | 在数据库中设置默认值 | |
server_onupdate | 在数据库中设置更新时的行为 |
首先我们建立用户表和文章表,其中用户和文章是一对多关系,User和Article表中的uid为逻辑外键,以下面的建立的engine和session来操作数据库。
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from enum import Enum
from sqlalchemy import Column, Integer, String, Enum as EnumType, DateTime, ForeignKey, Text, create_engine
from sqlalchemy.orm import sessionmaker, relationship
from sqlalchemy.sql import func
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.ext.hybrid import hybrid_method
Base = declarative_base()
class Gender(Enum):
male = '男'
female = '女'
unknown = '未知'
class User(Base):
__tablename__ = 't_user'
id = Column(Integer, primary_key=True)
name = Column(String(32), nullable=False, comment='姓名')
gender = Column(EnumType(Gender), nullable=False, comment='性别')
created_at = Column(DateTime, default=func.now(), nullable=False)
updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), nullable=False)
def __str__(self):
return self.id
@hybrid_method
def as_dict(self):
return {
'id': self.id,
'name': self.name,
'gender': self.gender.value,
'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
'updated_at': self.updated_at.strftime('%Y-%m-%d %H:%M:%S')
}
class Article(Base):
__tablename__ = 't_article'
id = Column(Integer, primary_key=True)
content = Column(Text, comment='文章內容')
uid = Column(Integer, ForeignKey('t_user.id'), comment='用戶id')
t_user = relationship("User", foreign_keys=uid)
created_at = Column(DateTime, default=func.now(), nullable=False)
updated_at = Column(DateTime, default=func.now(), onupdate=func.now(), nullable=False)
def __str__(self):
return self.id
@hybrid_method
def as_dict(self):
return {
'id': self.id,
'content': self.content,
'uid': self.uid,
'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
'updated_at': self.updated_at.strftime('%Y-%m-%d %H:%M:%S')
}
engine = create_engine('postgresql://postgres:postgres@host:port/database')
Session = sessionmaker(bind=engine)
session = Session()
# 创建表 所有继承了Base的类
Base.metadata.create_all(engine)
添加记录使用session来对数据库进行操作。
# 添加记录 单条
user_obj = User(name='test_user_1', gender=Gender.unknown)
session.add(user_obj)
session.commit()
# 添加记录 多条
user_obj_2 = User(name='test_user_2', gender=Gender.male)
user_obj_3 = User(name='test_user_3', gender=Gender.female)
session.add_all([user_obj_2, user_obj_3])
session.commit()
hybrid_method是SQLAlchemy 提供的一个装饰器,它可以将一个方法转换为一个混合属性,既可以像方法一样被调用,也可以像属性一样被访问。我们可以利用这个方法序列化字段。
# 使用示例
from sqlalchemy.ext.hybrid import hybrid_method
@hybrid_method
def as_dict(self):
return {
'id': self.id,
'name': self.name,
'gender': self.gender.value,
'created_at': self.created_at.strftime('%Y-%m-%d %H:%M:%S'),
'updated_at': self.updated_at.strftime('%Y-%m-%d %H:%M:%S')
}
users = session.query(User).all()
seria_data = [user.as_dict() for user in users]
print(seria_data)
users = session.query(User).all()
filter_by直接使用关键字参数指定过滤条件,但只能使用单个条件进行查询。使用 filter_by
方法时,必须确保过滤条件的列在查询表中是唯一的,否则会引发错误。
session.query(User).filter_by(name='test_user_1').all()
filter方法使用关键字参数指定查询条件,可以使用多个条件组合查询,可以处理更为复杂的查询
session.query(User).filter(User.name == 'Alice', User.id > 2).all()
用于按指定字段对查询结果进行排序
session.query(User).order_by(User.id.desc()).all()
用于按指定字段进行分组查询。
session.query(User.name, func.count(User.id)).group_by(User.name).all()
用于关联查询两个表
# 连表查询
result = session.query(User, Article).join(Article).all()
# 遍历查询结果
for user, article in result:
print(user.name, article.id, article.uid)
用于限制查询结果的数量。
session.query(User).order_by(User.id.desc()).limit(10).all()
用于指定查询结果的偏移量
session.query(User).order_by(User.age.desc()).offset(10).limit(10).all()
用于创建一个子查询
from sqlalchemy import select
subquery = select(User.id).filter_by(name='Alice').subquery()
session.query(Article).filter(Article.user_id.in_(subquery)).all()
用于去重查询结果
session.query(User.name).distinct().all()
用于对分组查询结果进行过滤。
from sqlalchemy import func
users = session.query(User.name, func.count(User.id)).group_by(User.name).having(func.count(User.id) > 1).all()
执行sql语句要避免SQL注入攻击,使用占位符 :field
和命名占位符 %
来避免。
from sqlalchemy import text
# 使用占位符传递参数
session.execute(text('SELECT * FROM table WHERE id=:id'), {'id': 1})
# 使用命名占位符传递参数
session.execute(text('SELECT * FROM table WHERE id=%(id)s'), {'id': 1})
方法名 | 含义 | 备注 |
---|---|---|
exists | 判断查询结果是否存在 | |
count | 统计查询结果的数量 | |
scalar | 获取查询结果的第一个字段 | |
first | 获取查询结果的第一条记录 | |
get | 根据主键获取一条记录 | get(pk) |
one | 获取查询结果的唯一一条记录 | |
all | 获取查询结果的所有记录 | |
one_or_none | 获取查询结果的唯一一条记录 | 查询结果为空或不唯一则返回 None |
delete | 删除记录 | |
update | 更新记录 | .update({‘field’: ‘val’}) |
scalar_subquery | 获取子查询的第一列第一行的值 |
可以使用 and_、or_、not_ 函数来组合多个查询条件,从而实现更为复杂的查询操作
运算符 | 含义 |
---|---|
== | 等于 |
!= | 不等于 |
< | 小于 |
> | 大于 |
<= | 小于等于 |
>= | 大于等于 |
like | 模糊匹配 |
in_ | 判断一个值是否在一个列表 |
notin_ | 判断一个值是否不在一个列表 |
is_ | 用于判断值 |
and_ | 与 |
or_ | 或 |
在数据库操作中,事务用来保证一组相关的数据库操作在执行过程中的一致性和完整性,即要么全部执行成功,要么全部执行失败。在 SQLAlchemy 中,使用 Session 进行事务操作。
# 使用示例
with session.begin():
user = User(name='Alice', age=25)
session.add(user)
在SQLAlchemy中,可以使用async_session()方法来创建异步会话。这个方法返回一个asyncio.Task 对象,可以在异步上下文中运行。异步会话需要在异步上下文中使用,即使用 async with 异步会话工厂() as session 的方式。此外,由于异步会话是异步的,因此在调用异步会话的方法时需要使用 await 关键字。
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession
from sqlalchemy.orm import sessionmaker
# 创建异步引擎
engine = create_async_engine('postgresql+asyncpg://user:password@host/dbname')
# 创建异步会话工厂
async_session_factory = sessionmaker(
engine,
expire_on_commit=False,
class_=AsyncSession
)
# 使用异步会话
async with async_session_factory() as session:
result = await session.execute(select(User).where(User.id == 1))
user = result.fetchone()
print(user)
Flask-SQLAlchemy是一个基于Flask的SQLAlchemy扩展,使得在 Flask 应用中使用SQLAlchemy 更加方便。它提供了一个 SQLAlchemy 实例db,可以在 Flask 应用中使用。使用Flask-SQLAlchemy,首先需要在 Flask 应用中创建一个SQLAlchemy实例,并配置连接数据库的URI。操作session和SQLalchemy一致。
使用示例:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config['SQLALCHEMY_DATABASE_URI'] = 'postgresql://postgres:postgres@host:port/database'
db = SQLAlchemy(app)
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(32))
email = db.Column(db.String(128))
# 创建表
db.create_all()
# 添加记录
user = User(name='John', email='[email protected]')
db.session.add(user)
db.session.commit()
# 查询操作
db.session.query(User).filter_by(name='John').order_by(User.id.desc()).all()
常用的 Flask-SQLAlchemy 配置参数:
参数 | 含义 |
---|---|
SQLALCHEMY_DATABASE_URI | 数据库连接字符串 |
SQLALCHEMY_TRACK_MODIFICATIONS | 是否追踪对象的修改并发送信号 |
SQLALCHEMY_ECHO | 是否打印 SQL 语句和执行时间等调试信息 |
SQLALCHEMY_POOL_SIZE | 数据库连接池的大小,默认为 5 |
SQLALCHEMY_MAX_OVERFLOW | 连接池中最多可增加的连接数,默认为10 |
SQLALCHEMY_POOL_TIMEOUT | 获取连接的超时时间,默认为10 秒 |
SQLALCHEMY_POOL_RECYCLE | 连接池中连接的最大寿命 |