1/3
2/3
3/3
【SQLAlchemy】ORM 关系映射框架了解与初步使用
阿提艾斯
2023年01月31日 12:06
收录于文集
共45篇

1. 认识SQLAlchemy

SQLAlchemy是Python SQL工具包对象关系映射器。它专为高校和高性能的数据库访问而设计。它支持连接SQLite、PostgreSQL、Oracle、MySQL/MariaDB、Microsoft SQL Server等等。

它提供了两种主要的使用模式:

  • SQLAlchemy Core,通过Table构造函数初始化Table对象。

  • ORM,通过定义一个类,继承declarative_base这个特殊基类(SQLAlchemy 2.0j继承的是DeclarativeBase,注意看官方文档),declarative_base会把元数据容器(类)和映射器(数据表)结合在一起。

目前官方SQLAlchemy最新版本为2.0.0。

无论使用哪种方式,都需要连接到数据库。需要创建一个SQLAlchemy引擎,创建引擎如下:

代码块
Python
自动换行
复制代码
from sqlalchemy import create_engine
# SQLite连接
engine = create_engine("sqlite:///:memory:", echo=True, future=True)
engine = create_engine("sqlite:///relative/path/to/file.db", echo=True, future=True)
engine = create_engine("sqlite:////absolute/path/to/file.db", echo=True, future=True)
复制成功

2. 使用ORM

以下例子使用SQLAlchemy 1.4.32实验,其他版本参考官方文档。

orm使用的类应该满足如下要求:

  • 继承自declarative_base对象

  • 包含__tablename__,数据库表名称

  • 包含一个或多个属性,它们都是Column对象

  • 确保一个或多个属性组成主键

2.1 声明模块

每个表都被定义为一个模块,在项目中只需要声明一次,它包含了数据库表的信息,比如表名称、列名称、列属性等元数据。

代码块
Python
自动换行
复制代码
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import declarative_base, relationship

Base = declarative_base()


class User(Base):
    __tablename__ = "user_account"
    id = Column(Integer, primary_key=True)
    name = Column(String(30))
    fullname = Column(String)
    addresses = relationship("Address", back_populates="user", cascade="all, delete-orphan")

    def __repr__(self):
        return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"


class Address(Base):
    __tablename__ = "address"

    id = Column(Integer, primary_key=True)
    email_address = Column(String, nullable=False)
    user_id = Column(Integer, ForeignKey("user_account.id"), nullable=False)
    user = relationship("User", back_populates="addresses")

    def __repr__(self):
        return f"Address(id={self.id!r}, email_address={self.email_address!r})"
复制成功

relationship()表示在两个ORM类之间进行联动,比如User的addresses属性关联到Address,Address的user属性关联到User,更深层的用法待补充。

2.2 创建引擎

引擎能为我们创建新的数据库连接,它是维持在连接池里的,方便复用。

代码块
Python
自动换行
复制代码
from sqlalchemy import create_engine
# 创建引擎连接
engine = create_engine("sqlite:///test.sqlite", echo=True, future=True)
# 创建表
Base.metadata.create_all(engine)
复制成功

echo=True,会将表创建语句记录在标准输出里。程序会自动创建test.sqlite数据库文件。

运行日志如下:

2.3 插入数据

创建的模块实例如果要持久化到数据库中,需要调用会话Session,Session会和数据库进行交互,它封装了一个事务,这个事务将一直保持打开状态,直到会话提交或回滚。看下方例子:

代码块
Python
自动换行
复制代码
# 插入数据
with Session(engine) as session:
    xiaoming = User(
        name="xiaoming",
        fullname="Zhang Xiaoming",
        addresses=[Address(email_address='xiaoming@qq.com')]
    )

    xiaowu = User(
        name="xiaowu",
        fullname="Zhang Xiaowu"
    )

    xiaoliu = User(
        name="xiaoliu",
        fullname="Zhang Xiaoliu",
        addresses=[Address(email_address='xiaoliu@qq.com'),
                   Address(email_address='xiaoliu@ww.com')]
    )
    # 将实例添加到表里
    session.add_all([xiaowu, xiaoliu, xiaoming])
    # 提交事务,刷新到数据库中
    session.commit()
复制成功

session.add_all可以一次性添加多个对象实例。

session.add一次添加一个实例。

从日志看就是提交了一个事务,从数据库表里看用户表和地址表数据都插入成功了,

2.4 查询数据

2.4.1 单表查询

查询数据使用到sqlalchemy的select方法,where中指明条件,session.scalars会返回一个可迭代对象ScalarResult。

代码块
Python
自动换行
复制代码
from sqlalchemy import select
# 查询数据
with Session(engine) as session:
    result = select(User).where(User.name.in_(["xiaowu", "xiaoliu"]))
    for user in session.scalars(result):
        print(user)
复制成功

下方为查询语句和查询结果:

2.4.2 多表查询

查询xiaoliu的地址信息

代码块
Python
自动换行
复制代码
# join查询
result = select(Address).join(Address.user).where(User.name=='xiaoliu').\
    where(Address.email_address == 'xiaoliu@qq.com')
with Session(engine) as session:
    s = session.scalars(result).one()
    print(s)
复制成功

查询结果:

2.5 更新数据

例子:

把xiaowu的全名修改为Zhang Xiaowu Hahaha,地址追加"xiaowu@ll.com"

代码块
Python
自动换行
复制代码
# 更新数据
stmt = select(User).where(User.name == "xiaowu")
with Session(engine) as session:
    xiaowu_info = session.scalars(stmt).one()
    xiaowu_info.addresses.append(Address(email_address="xiaowu@ll.com"))
    xiaowu_info.fullname = "Zhang Xiaowu Hahaha"
    session.commit()
复制成功

运行结果:

2.6 删除数据

例子:删除xiaowu的账号和地址信息

代码块
Python
自动换行
复制代码
# 删除数据
with Session(engine) as session:
    # 获取xiaowu的账户信息
    xiaowu = session.get(User, 1)
    session.delete(xiaowu)
    session.commit()
复制成功

运行结果:xiaowu的账号信息和地址信息均删除。

3. 参考资料

  • SQLAlchemy官方文档:https://www.sqlalchemy.org/

  • Python库之SQLAlchemy: https://zhuanlan.zhihu.com/p/265224273