SqlAlchemy使用入门

官方文档:https://docs.sqlalchemy.org/

​  SQLAlchemy是一个Python的SQL工具ORM 框架,提供了丰富的SQL操作和数据持久化功能,支持多种数据库,包括 PostgreSQL、MySQL、Oracle、SQLite 等。SQLAlchemy分为SQL Expression Language和ORM两部分。

SqlAlchemy使用入门_第1张图片

SQLAlchemy 的优缺点

优点:

  • 支持多种数据库,可以无缝切换数据库类型。
  • 提供了多种 SQL 操作和查询方式,可以灵活处理复杂的 SQL 操作和数据查询。
  • ORM功能丰富,提供了多种映射关系的方式,可以灵活处理对象和表之间的关系。
  • 支持连接池和事务管理等功能,可以提高数据库的性能和可靠性。

缺点:

  • 学习曲线较陡峭,需要一定的学习成本。
  • 代码量较多,可能会增加代码复杂度。
  • ORM 功能相对于其他 Python 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 在数据库中设置更新时的行为

SQLAlchemy操作

​  首先我们建立用户表和文章表,其中用户和文章是一对多关系,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()

1、 建表

# 创建表    所有继承了Base的类
Base.metadata.create_all(engine)

2、 添加记录

添加记录使用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()

3、 查询

3.1 查询结果序列化

​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)

3.2 query

users = session.query(User).all()

3.3 filter_by

filter_by直接使用关键字参数指定过滤条件,但只能使用单个条件进行查询。使用 filter_by 方法时,必须确保过滤条件的列在查询表中是唯一的,否则会引发错误。

session.query(User).filter_by(name='test_user_1').all()

3.4 filter

filter方法使用关键字参数指定查询条件,可以使用多个条件组合查询,可以处理更为复杂的查询

session.query(User).filter(User.name == 'Alice', User.id > 2).all()

3.5 order_by

用于按指定字段对查询结果进行排序

session.query(User).order_by(User.id.desc()).all()

3.6 group_by

用于按指定字段进行分组查询。

session.query(User.name, func.count(User.id)).group_by(User.name).all()

3.7 join

用于关联查询两个表

# 连表查询
result = session.query(User, Article).join(Article).all()

# 遍历查询结果
for user, article in result:
     print(user.name, article.id, article.uid)

3.8 limit

用于限制查询结果的数量。

session.query(User).order_by(User.id.desc()).limit(10).all()

3.9 offset

用于指定查询结果的偏移量

 session.query(User).order_by(User.age.desc()).offset(10).limit(10).all()

3.10 subquery

用于创建一个子查询

from sqlalchemy import select

subquery = select(User.id).filter_by(name='Alice').subquery()
session.query(Article).filter(Article.user_id.in_(subquery)).all()

3.11 distinct

用于去重查询结果

session.query(User.name).distinct().all()

3.12 having

用于对分组查询结果进行过滤。

from sqlalchemy import func

users = session.query(User.name, func.count(User.id)).group_by(User.name).having(func.count(User.id) > 1).all()

3.13 执行 SQL 原生语句

执行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})

4、 获取结果

方法名 含义 备注
exists 判断查询结果是否存在
count 统计查询结果的数量
scalar 获取查询结果的第一个字段
first 获取查询结果的第一条记录
get 根据主键获取一条记录 get(pk)
one 获取查询结果的唯一一条记录
all 获取查询结果的所有记录
one_or_none 获取查询结果的唯一一条记录 查询结果为空或不唯一则返回 None
delete 删除记录
update 更新记录 .update({‘field’: ‘val’})
scalar_subquery 获取子查询的第一列第一行的值

5、 查询运算符

可以使用 and_、or_、not_ 函数来组合多个查询条件,从而实现更为复杂的查询操作

运算符 含义
== 等于
!= 不等于
< 小于
> 大于
<= 小于等于
>= 大于等于
like 模糊匹配
in_ 判断一个值是否在一个列表
notin_ 判断一个值是否不在一个列表
is_ 用于判断值
and_
or_

6、事务使用

在数据库操作中,事务用来保证一组相关的数据库操作在执行过程中的一致性和完整性,即要么全部执行成功,要么全部执行失败。在 SQLAlchemy 中,使用 Session 进行事务操作。

# 使用示例
with session.begin():
	    user = User(name='Alice', age=25)
	    session.add(user)

SqlAlchemy开启异步会话

  在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)

falsk_sqlalchemy使用

  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 连接池中连接的最大寿命

你可能感兴趣的:(数据库,python,orm)