SqlAlchemy 2.0 中文文档(五十七)(7)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS SQL Server Serverless,2-4RCU 50GB 3个月
推荐场景:
简介: SqlAlchemy 2.0 中文文档(五十七)

SqlAlchemy 2.0 中文文档(五十七)(6)https://developer.aliyun.com/article/1563168


优化的 ORM 批量插入现在已经针对除 MySQL 之外的所有后端实现了

1.4 系列中引入的显著性能改进,如 ORM Batch inserts with psycopg2 now batch  statements with RETURNING in most cases 中所述,现已普遍适用于所有支持 RETURNING 的后端,除了  MySQL:SQLite、MariaDB、PostgreSQL(所有驱动程序)和 Oracle;SQL Server 有支持,但在版本  2.0.9 中暂时禁用 [1]。虽然原始功能对于 psycopg2 驱动程序至关重要,否则在使用 cursor.executemany() 时存在严重的性能问题,但对于其他 PostgreSQL 驱动程序,如 asyncpg,此更改也至关重要,因为在使用 RETURNING  时,单语句 INSERT 语句仍然不可接受地缓慢,以及在使用 SQL Server 时,无论是否使用 RETURNING,插入语句的  executemany 速度也似乎非常缓慢。

新功能的性能为每个驱动程序的 INSERT ORM 对象的性能提供了几乎横跨所有板块的数量级的性能提升,如下表所示,大多数情况下特定于 RETURNING 的使用,通常不支持 executemany()。

psycopg2 的“快速执行助手”方法包括将具有单个参数集的 INSERT…RETURNING  语句转换为一个插入多个参数集的单个语句,使用多个“VALUES…”子句,以便它可以一次容纳多个参数集。然后,参数集通常被批处理成一组 1000  或类似的参数集,以便没有单个 INSERT 语句过于大,并且 INSERT 语句然后针对每个参数批次调用,而不是针对每个单独的参数集。通过  RETURNING 返回主键值和服务器默认值,这仍然会在每个语句执行时使用 cursor.execute() 调用,而不是 cursor.executemany()

这允许一次插入许多行,同时还能够返回新生成的主键值以及 SQL 和服务器默认值。历史上,SQLAlchemy 一直需要对每个参数集调用一条语句,因为它依赖于诸如 cursor.lastrowid 等 Python DBAPI 功能,这些功能不支持多行。

由于现在大多数数据库都提供了 RETURNING(尤其是 MySQL 是一个明显的例外,因为 MariaDB 支持它),新的更改将  psycopg2 的“快速执行助手”方法推广到支持 RETURNING 的所有方言,现在包括 SQlite 和  MariaDB,并且对于没有其他方法来执行“executemany 加 RETURNING”的方言,包括 SQLite、MariaDB 和所有  PG 驱动程序。用于 Oracle 支持 RETURNING 的 cx_Oracle 和 oracledb 驱动程序会在本机支持  executemany,这也已经实现了相应的性能改进。由于 SQLite 和 MariaDB 现在提供 RETURNING 支持,ORM 对cursor.lastrowid的使用几乎成为历史,只有 MySQL 仍然依赖于它。

对于不使用 RETURNING 的 INSERT 语句,对于大多数后端,都使用传统的 executemany()行为,当前的例外是  psycopg2,它的 executemany()性能总体上非常慢,并且仍然受到“insertmanyvalues”方法的改进。

基准测试

SQLAlchemy 在examples/目录中包含一个性能套件,在这里我们可以利用bulk_insert套件以不同的方式使用 Core 和 ORM 来对插入多行的 INSERT 进行基准测试。

对于下面的测试,我们插入了100,000 个对象,在所有情况下,我们实际上都有 100,000 个真实的 Python ORM 对象在内存中,无论是预先创建的还是动态生成的。除了 SQLite 之外的所有数据库都通过本地网络连接运行,而不是本地主机;这导致“较慢”的结果非常慢。

此功能改进的操作包括:

  • 使用Session.add()Session.add_all()将对象添加到会话中的工作单元刷新。
  • 新的 ORM 批量插入语句功能,改进了 SQLAlchemy 1.4 中首次引入的此功能的试验版本。
  • 在批量操作中描述的Session “批量”操作,这些操作被上述 ORM 批量插入功能所取代。

为了对操作的规模有所了解,以下是使用test_flush_no_pk性能套件的性能测量结果,该套件历史上代表了 SQLAlchemy 的最坏情况 INSERT 性能任务,其中需要插入没有主键值的对象,然后必须获取新生成的主键值,以便对象可以用于后续的 flush 操作,例如在关系中建立关系,刷新连接继承模型等:

@Profiler.profile
def test_flush_no_pk(n):
  """INSERT statements via the ORM (batched with RETURNING if available),
 fetching generated row id"""
    session = Session(bind=engine)
    for chunk in range(0, n, 1000):
        session.add_all(
            [
                Customer(
                    name="customer name %d" % i,
                    description="customer description %d" % i,
                )
                for i in range(chunk, chunk + 1000)
            ]
        )
        session.flush()
    session.commit()

可以从任何 SQLAlchemy 源代码树中运行此测试,如下所示:

python -m examples.performance.bulk_inserts --test test_flush_no_pk

下表总结了最新的 1.4 系列 SQLAlchemy 与 2.0 的性能测量结果,两者都运行相同的测试:

驱动程序 SQLA 1.4 时间(秒) SQLA 2.0 时间(秒)
sqlite+pysqlite2 (内存) 6.204843 3.554856
postgresql+asyncpg (网络) 88.292285 4.561492
postgresql+psycopg (网络) N/A (psycopg3) 4.861368
mssql+pyodbc (网络) 158.396667 4.825139
oracle+cx_Oracle (网络) 92.603953 4.809520
mariadb+mysqldb (网络) 71.705197 4.075377

注意

另外两个驱动程序在性能上没有变化;psycopg2 驱动程序,其在 SQLAlchemy 1.4 中已经实现了快速 executemany,以及 MySQL,它仍然不提供 RETURNING 支持:

驱动程序 SQLA 1.4 时间(秒) SQLA 2.0 时间(秒)
postgresql+psycopg2 (网络) 4.704876 4.699883
mysql+mysqldb (网络) 77.281997 76.132995

变更摘要

以下项目列出了 2.0 版本中为使所有驱动程序达到这种状态所做的各项更改:

  • SQLite 实现了 RETURNING - #6195
  • MariaDB 实现了 RETURNING - #7011
  • 修复 Oracle 的多行 RETURNING - #6245
  • 使 insert() executemany() 支持尽可能多的方言的 RETURNING,通常使用 VALUES() - #6047
  • 当对不支持的后端使用 RETURNING w/ executemany 时发出警告(当前没有 RETURNING 后端有此限制)- #7907
  • ORM Mapper.eager_defaults 参数现在默认为新设置 "auto",当使用的后端支持带有“insertmanyvalues”的 RETURNING 时,将自动启用“eager defaults”用于 INSERT 语句。请参阅获取服务器生成的默认值以获取文档。

另请参阅

INSERT 语句的“Insert Many Values”行为 - 新功能的文档和背景以及如何配置它

基准测试

SQLAlchemy 在 examples/ 目录中包含一个性能套件,在这里我们可以利用 bulk_insert 套件以不同方式使用 Core 和 ORM 来对插入多行的性能进行基准测试。

对于下面的测试,我们插入了100,000 个对象,在所有情况下,我们实际上在内存中有 100,000 个真实的 Python ORM 对象,要么事先创建,要么动态生成。除 SQLite 外的所有数据库都通过本地网络连接运行,而不是 localhost;这导致“较慢”的结果非常慢。

通过这个功能改进的操作包括:

  • 通过Session.add()Session.add_all()向会话添加的对象的工作单元刷新。
  • 新的 ORM 批量插入语句功能,改进了首次在 SQLAlchemy 1.4 中引入的此功能的实验版本。
  • Session中描述的“bulk”操作,已被上述 ORM 批量插入功能取代。

为了了解操作的规模,以下是使用test_flush_no_pk性能套件进行的性能测量,这通常代表 SQLAlchemy 的最坏情况 INSERT 性能任务,其中需要 INSERT 没有主键值的对象,然后必须获取新生成的主键值,以便这些对象可以用于后续的 flush 操作,比如在关系中建立,刷新加入继承模型等:

@Profiler.profile
def test_flush_no_pk(n):
  """INSERT statements via the ORM (batched with RETURNING if available),
 fetching generated row id"""
    session = Session(bind=engine)
    for chunk in range(0, n, 1000):
        session.add_all(
            [
                Customer(
                    name="customer name %d" % i,
                    description="customer description %d" % i,
                )
                for i in range(chunk, chunk + 1000)
            ]
        )
        session.flush()
    session.commit()

可以从任何 SQLAlchemy 源代码树中运行此测试:

python -m examples.performance.bulk_inserts --test test_flush_no_pk

下表总结了最新的 SQLAlchemy 1.4 系列与 2.0 之间的性能测量结果,两者都运行相同的测试:

驱动程序 SQLA 1.4 时间(秒) SQLA 2.0 时间(秒)
sqlite+pysqlite2 (内存) 6.204843 3.554856
postgresql+asyncpg (网络) 88.292285 4.561492
postgresql+psycopg (网络) N/A (psycopg3) 4.861368
mssql+pyodbc (网络) 158.396667 4.825139
oracle+cx_Oracle (网络) 92.603953 4.809520
mariadb+mysqldb (网络) 71.705197 4.075377

注意

另外两个驱动程序在性能上没有变化;对于已在 SQLAlchemy 1.4 中实现了快速 executemany 的 psycopg2 驱动程序以及继续不提供 RETURNING 支持的 MySQL:

驱动程序 SQLA 1.4 时间(秒) SQLA 2.0 时间(秒)
postgresql+psycopg2 (网络) 4.704876 4.699883
mysql+mysqldb (网络) 77.281997 76.132995

变更摘要

以下项目列出了 2.0 中进行的各项更改,以使所有驱动程序达到此状态:

  • 为 SQLite 实现了 RETURNING - #6195
  • 为 MariaDB 实现了 RETURNING - #7011
  • 修复了 Oracle 的多行 RETURNING - #6245
  • 使 insert() executemany()支持尽可能多的方言,通常使用 VALUES() - #6047
  • 当用于不支持的后端时发出警告 RETURNING w/ executemany(当前没有 RETURNING 后端具有此限制)- #7907
  • ORM Mapper.eager_defaults参数现在默认为一个新设置 "auto", 当使用的后端支持带有“insertmanyvalues”的 RETURNING 时,会自动为 INSERT 语句启用“急切默认”。请参阅获取服务器生成的默认值了解文档。

另请参阅

INSERT 语句的“Insert Many Values”行为 - 新功能的文档和背景,以及如何配置它

启用 ORM 的插入、更新和删除语句,带有 ORM RETURNING

SQLAlchemy 1.4 将遗留的Query对象的特性移植到 2.0 样式执行,这意味着Select构造可以传递给Session.execute()以传递 ORM 结果。还增加了对UpdateDelete的支持,以便它们可以提供Query.update()Query.delete()的实现。

主要缺失的元素是对Insert构造的支持。1.4 文档通过使用Select.from_statement()的一些“插入”和“更新”配方来解决这个问题,将 RETURNING 集成到 ORM 上下文中。2.0 现在通过将Insert的直接支持整合为增强版本的Session.bulk_insert_mappings()方法以及对所有 DML 结构的完整 ORM RETURNING 支持来完全填补了这一空白。

带有 RETURNING 的批量插入

Insert 可以传递给 Session.execute(),可以带有或不带有 Insert.returning(),当传递给一个单独的参数列表时,将调用与以前由 Session.bulk_insert_mappings() 实现的相同的过程,同时增强了附加功能。这将优化使用新的快速插入功能的行批处理,同时还添加了对异构参数集和多表映射(如联合表继承)的支持:

>>> users = session.scalars(
...     insert(User).returning(User),
...     [
...         {"name": "spongebob", "fullname": "Spongebob Squarepants"},
...         {"name": "sandy", "fullname": "Sandy Cheeks"},
...         {"name": "patrick", "fullname": "Patrick Star"},
...         {"name": "squidward", "fullname": "Squidward Tentacles"},
...         {"name": "ehkrabs", "fullname": "Eugene H. Krabs"},
...     ],
... )
>>> print(users.all())
[User(name='spongebob', fullname='Spongebob Squarepants'),
 User(name='sandy', fullname='Sandy Cheeks'),
 User(name='patrick', fullname='Patrick Star'),
 User(name='squidward', fullname='Squidward Tentacles'),
 User(name='ehkrabs', fullname='Eugene H. Krabs')]

RETURNING 支持所有这些用例,ORM 将从多个语句调用中构造完整的结果集。

另请参阅

ORM 大规模插入语句

大规模 UPDATE

Insert 类似,将 Update 构造传递给包含主键值的参数列表的 Session.execute() 将调用之前由 Session.bulk_update_mappings() 方法支持的相同过程。但是,该功能不支持 RETURNING,因为它使用一个 SQL UPDATE 语句,该语句使用 DBAPI 的 executemany 调用:

>>> from sqlalchemy import update
>>> session.execute(
...     update(User),
...     [
...         {"id": 1, "fullname": "Spongebob Squarepants"},
...         {"id": 3, "fullname": "Patrick Star"},
...     ],
... )

另请参阅

按主键进行 ORM 大规模 UPDATE

插入/ upsert … VALUES … RETURNING

使用 Insert 时,可在 Insert.values() 中包含一组参数,其中可能包括 SQL 表达式。此外,还支持 SQLite、PostgreSQL 和 MariaDB 的 upsert 变体。这些语句现在可以包含 Insert.returning() 子句,其中包括列表达式或完整的 ORM 实体:

>>> from sqlalchemy.dialects.sqlite import insert as sqlite_upsert
>>> stmt = sqlite_upsert(User).values(
...     [
...         {"name": "spongebob", "fullname": "Spongebob Squarepants"},
...         {"name": "sandy", "fullname": "Sandy Cheeks"},
...         {"name": "patrick", "fullname": "Patrick Star"},
...         {"name": "squidward", "fullname": "Squidward Tentacles"},
...         {"name": "ehkrabs", "fullname": "Eugene H. Krabs"},
...     ]
... )
>>> stmt = stmt.on_conflict_do_update(
...     index_elements=[User.name], set_=dict(fullname=stmt.excluded.fullname)
... )
>>> result = session.scalars(stmt.returning(User))
>>> print(result.all())
[User(name='spongebob', fullname='Spongebob Squarepants'),
User(name='sandy', fullname='Sandy Cheeks'),
User(name='patrick', fullname='Patrick Star'),
User(name='squidward', fullname='Squidward Tentacles'),
User(name='ehkrabs', fullname='Eugene H. Krabs')]

另请参阅

使用每行 SQL 表达式进行 ORM 大规模插入

ORM “upsert” 语句

ORM UPDATE / DELETE with WHERE … RETURNING

SQLAlchemy 1.4 还对与update()delete()构造一起使用时与Session.execute()一起使用 RETURNING 功能提供了一些有限的支持。现在,此支持已经升级为完全本地化,包括fetch同步策略也可以继续进行,无论是否明确使用 RETURNING:

>>> from sqlalchemy import update
>>> stmt = (
...     update(User)
...     .where(User.name == "squidward")
...     .values(name="spongebob")
...     .returning(User)
... )
>>> result = session.scalars(stmt, execution_options={"synchronize_session": "fetch"})
>>> print(result.all())

另请参阅

使用自定义 WHERE 条件的 ORM UPDATE 和 DELETE

使用 RETURNING 进行 UPDATE/DELETE 和自定义 WHERE 条件

改进的 ORM UPDATE / DELETE 的synchronize_session行为

synchronize_session 的默认策略现在是一个新值"auto"。此策略将尝试使用"evaluate"策略,然后自动回退到"fetch"策略。除了 MySQL / MariaDB 之外的所有后端,"fetch"使用 RETURNING 在同一语句中获取 UPDATE/DELETE 的主键标识符,因此通常比以前的版本更有效(在 1.4 中,RETURNING 仅适用于 PostgreSQL、SQL Server)。

另请参阅

选择同步策略

变更摘要

新的 ORM DML 带有 RETURNING 功能的列出的票据:

  • 将 ORM 级别的insert()转换为在 ORM 上下文中解释values() - #7864
  • 评估dml.returning(Entity)的可行性,以提供 ORM 表达式,自动应用select().from_statement等效 - #7865
  • 给定 ORM 插入,尝试沿用批量方法,关于继承 - #8360

带有 RETURNING 的批量插入

Insert可以传递给Session.execute(),可以带有或不带有Insert.returning(),当与单独的参数列表一起传递时,将调用与以前由Session.bulk_insert_mappings()实现的相同过程,同时增加了额外的增强功能。这将优化行的批处理,利用新的快速插入多行功能,同时还支持异构参数集和多表映射,如联合表继承:

>>> users = session.scalars(
...     insert(User).returning(User),
...     [
...         {"name": "spongebob", "fullname": "Spongebob Squarepants"},
...         {"name": "sandy", "fullname": "Sandy Cheeks"},
...         {"name": "patrick", "fullname": "Patrick Star"},
...         {"name": "squidward", "fullname": "Squidward Tentacles"},
...         {"name": "ehkrabs", "fullname": "Eugene H. Krabs"},
...     ],
... )
>>> print(users.all())
[User(name='spongebob', fullname='Spongebob Squarepants'),
 User(name='sandy', fullname='Sandy Cheeks'),
 User(name='patrick', fullname='Patrick Star'),
 User(name='squidward', fullname='Squidward Tentacles'),
 User(name='ehkrabs', fullname='Eugene H. Krabs')]

对于所有这些用例,都支持 RETURNING,其中 ORM 将从多个语句调用构造完整的结果集。

另请参阅

ORM 批量插入语句

批量更新

Insert类似,将Update构造与包含主键值的参数列表一起传递给Session.execute()将调用与之前由Session.bulk_update_mappings()方法支持的相同过程。但是,此功能不支持 RETURNING,因为它使用了通过 DBAPI executemany 调用的 SQL UPDATE 语句:

>>> from sqlalchemy import update
>>> session.execute(
...     update(User),
...     [
...         {"id": 1, "fullname": "Spongebob Squarepants"},
...         {"id": 3, "fullname": "Patrick Star"},
...     ],
... )

另请参阅

按主键批量更新的 ORM UPDATE

INSERT / upsert … VALUES … RETURNING

当使用InsertInsert.values()时,参数集合可以包含 SQL 表达式。此外,还支持 SQLite、PostgreSQL 和 MariaDB 等数据库的 upsert 变体。这些语句现在可以包括带有列表达式或完整 ORM 实体的Insert.returning()子句:

>>> from sqlalchemy.dialects.sqlite import insert as sqlite_upsert
>>> stmt = sqlite_upsert(User).values(
...     [
...         {"name": "spongebob", "fullname": "Spongebob Squarepants"},
...         {"name": "sandy", "fullname": "Sandy Cheeks"},
...         {"name": "patrick", "fullname": "Patrick Star"},
...         {"name": "squidward", "fullname": "Squidward Tentacles"},
...         {"name": "ehkrabs", "fullname": "Eugene H. Krabs"},
...     ]
... )
>>> stmt = stmt.on_conflict_do_update(
...     index_elements=[User.name], set_=dict(fullname=stmt.excluded.fullname)
... )
>>> result = session.scalars(stmt.returning(User))
>>> print(result.all())
[User(name='spongebob', fullname='Spongebob Squarepants'),
User(name='sandy', fullname='Sandy Cheeks'),
User(name='patrick', fullname='Patrick Star'),
User(name='squidward', fullname='Squidward Tentacles'),
User(name='ehkrabs', fullname='Eugene H. Krabs')]

另请参阅

使用每行 SQL 表达式的 ORM 批量插入

ORM “upsert” 语句

带 WHERE … RETURNING 的 ORM UPDATE / DELETE

SQLAlchemy 1.4 也对与update()delete()构造一起使用时与Session.execute()一起使用 RETURNING 功能提供了一些有限支持。此支持现已升级为完全本机,包括fetch同步策略也可以继续进行,无论是否存在显式使用 RETURNING:

>>> from sqlalchemy import update
>>> stmt = (
...     update(User)
...     .where(User.name == "squidward")
...     .values(name="spongebob")
...     .returning(User)
... )
>>> result = session.scalars(stmt, execution_options={"synchronize_session": "fetch"})
>>> print(result.all())

另请参阅

使用自定义 WHERE 条件的 ORM UPDATE 和 DELETE

使用 UPDATE/DELETE 和自定义 WHERE 条件的 RETURNING

ORM UPDATE / DELETE 的改进synchronize_session行为

synchronize_session 的默认策略现在是一个新值"auto"。此策略将尝试使用"evaluate"策略,然后自动回退到"fetch"策略。对于除 MySQL / MariaDB 之外的所有后端,"fetch"使用 RETURNING 在同一语句中获取 UPDATE/DELETE 的主键标识符,因此通常比以前的版本更有效率(在 1.4 中,RETURNING 仅适用于 PostgreSQL,SQL Server)。

另请参阅

选择同步策略

变更摘要

新 ORM DML 的带有 RETURNING 特性的已列出的票证:

  • 将 ORM 级别的insert()转换为在 ORM 上下文中解释values()- #7864
  • 评估 dml.returning(Entity)提供 ORM 表达式的可行性,自动应用 select().from_statement 等效 - #7865
  • 给定 ORM 插入,尝试沿用批量方法,即继承关系- #8360

新的“只写”关系策略取代了“动态”

lazy="dynamic"加载策略已经过时,因为它是硬编码的,使用了遗留的Query。这种加载策略既不兼容 asyncio,而且还有许多行为会隐式地迭代其内容,这些行为背离了“动态”关系最初的目的,即针对不应在任何时候隐式完全加载到内存中的非常大的集合。

“动态”策略现已由新策略lazy="write_only"取代。可以使用relationship()relationship.lazy参数进行“只写”配置,或者在使用类型注释映射时,将WriteOnlyMapped注释指示为映射样式:

from sqlalchemy.orm import WriteOnlyMapped
class Base(DeclarativeBase):
    pass
class Account(Base):
    __tablename__ = "account"
    id: Mapped[int] = mapped_column(primary_key=True)
    identifier: Mapped[str]
    account_transactions: WriteOnlyMapped["AccountTransaction"] = relationship(
        cascade="all, delete-orphan",
        passive_deletes=True,
        order_by="AccountTransaction.timestamp",
    )
class AccountTransaction(Base):
    __tablename__ = "account_transaction"
    id: Mapped[int] = mapped_column(primary_key=True)
    account_id: Mapped[int] = mapped_column(
        ForeignKey("account.id", ondelete="cascade")
    )
    description: Mapped[str]
    amount: Mapped[Decimal]
    timestamp: Mapped[datetime] = mapped_column(default=func.now())

写入仅映射集合类似于lazy="dynamic",因为集合可以提前分配,并且还具有WriteOnlyCollection.add()WriteOnlyCollection.remove()等方法,以逐个项目的方式修改集合:

new_account = Account(
    identifier="account_01",
    account_transactions=[
        AccountTransaction(description="initial deposit", amount=Decimal("500.00")),
        AccountTransaction(description="transfer", amount=Decimal("1000.00")),
        AccountTransaction(description="withdrawal", amount=Decimal("-29.50")),
    ],
)
new_account.account_transactions.add(
    AccountTransaction(description="transfer", amount=Decimal("2000.00"))
)

在数据库加载方面的主要区别在于,该集合没有直接从数据库加载对象的能力;相反,使用 SQL 构造方法,如 WriteOnlyCollection.select() 来生成 SQL 构造,比如 Select,然后使用 2.0 风格 显式加载所需对象:

account_transactions = session.scalars(
    existing_account.account_transactions.select()
    .where(AccountTransaction.amount < 0)
    .limit(10)
).all()

WriteOnlyCollection 也与新的 ORM bulk dml 功能集成,包括支持带有 WHERE 条件的批量 INSERT 和 UPDATE/DELETE,所有这些都包括 RETURNING 支持。请参阅完整文档 Write Only Relationships。

另请参阅

Write Only Relationships

动态关系的新 pep-484 / 类型注释映射支持

尽管“动态”关系在 2.0 中是遗留的,但由于这些模式预计具有较长的生命周期,类型注释映射 现在已添加到“动态”关系中,与新的 lazy="write_only" 方法可用的方式相同,使用 DynamicMapped 注释:

from sqlalchemy.orm import DynamicMapped
class Base(DeclarativeBase):
    pass
class Account(Base):
    __tablename__ = "account"
    id: Mapped[int] = mapped_column(primary_key=True)
    identifier: Mapped[str]
    account_transactions: DynamicMapped["AccountTransaction"] = relationship(
        cascade="all, delete-orphan",
        passive_deletes=True,
        order_by="AccountTransaction.timestamp",
    )
class AccountTransaction(Base):
    __tablename__ = "account_transaction"
    id: Mapped[int] = mapped_column(primary_key=True)
    account_id: Mapped[int] = mapped_column(
        ForeignKey("account.id", ondelete="cascade")
    )
    description: Mapped[str]
    amount: Mapped[Decimal]
    timestamp: Mapped[datetime] = mapped_column(default=func.now())

上述映射将提供一个 Account.account_transactions 集合,其类型为 AppenderQuery 集合类型,包括其元素类型,例如 AppenderQuery[AccountTransaction]。然后允许迭代和查询产生类型为 AccountTransaction 的对象。

另请参阅

动态关系加载器

#7123

动态关系的新 pep-484 / 类型注释映射支持

尽管“动态”关系在 2.0 中是遗留的,但由于这些模式预计具有较长的生命周期,类型注释映射 现在已添加到“动态”关系中,与新的 lazy="write_only" 方法可用的方式相同,使用 DynamicMapped 注释:

from sqlalchemy.orm import DynamicMapped
class Base(DeclarativeBase):
    pass
class Account(Base):
    __tablename__ = "account"
    id: Mapped[int] = mapped_column(primary_key=True)
    identifier: Mapped[str]
    account_transactions: DynamicMapped["AccountTransaction"] = relationship(
        cascade="all, delete-orphan",
        passive_deletes=True,
        order_by="AccountTransaction.timestamp",
    )
class AccountTransaction(Base):
    __tablename__ = "account_transaction"
    id: Mapped[int] = mapped_column(primary_key=True)
    account_id: Mapped[int] = mapped_column(
        ForeignKey("account.id", ondelete="cascade")
    )
    description: Mapped[str]
    amount: Mapped[Decimal]
    timestamp: Mapped[datetime] = mapped_column(default=func.now())

上述映射将提供一个类型为返回AppenderQuery集合类型的Account.account_transactions集合,包括其元素类型,例如AppenderQuery[AccountTransaction]。这样就允许迭代和查询产生类型为AccountTransaction的对象。

另请参阅

动态关系加载器

#7123


SqlAlchemy 2.0 中文文档(五十七)(8)https://developer.aliyun.com/article/1563170

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助 &nbsp; &nbsp; 相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
3月前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(七十四)(5)
SqlAlchemy 2.0 中文文档(七十四)
46 6
|
3月前
|
SQL 关系型数据库 数据库
SqlAlchemy 2.0 中文文档(七十四)(3)
SqlAlchemy 2.0 中文文档(七十四)
43 1
|
3月前
|
SQL Python
SqlAlchemy 2.0 中文文档(七十四)(4)
SqlAlchemy 2.0 中文文档(七十四)
30 6
|
3月前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(七十四)(1)
SqlAlchemy 2.0 中文文档(七十四)
60 1
|
3月前
|
SQL 缓存 关系型数据库
SqlAlchemy 2.0 中文文档(七十四)(2)
SqlAlchemy 2.0 中文文档(七十四)
32 1
|
3月前
|
SQL 关系型数据库 MySQL
SqlAlchemy 2.0 中文文档(五十七)(1)
SqlAlchemy 2.0 中文文档(五十七)
37 0
|
3月前
|
SQL Python
SqlAlchemy 2.0 中文文档(五十七)(5)
SqlAlchemy 2.0 中文文档(五十七)
17 0
|
3月前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(五十七)(9)
SqlAlchemy 2.0 中文文档(五十七)
54 0
|
3月前
|
SQL Oracle 关系型数据库
SqlAlchemy 2.0 中文文档(五十七)(3)
SqlAlchemy 2.0 中文文档(五十七)
25 0
|
3月前
|
SQL 存储 测试技术
SqlAlchemy 2.0 中文文档(五十七)(4)
SqlAlchemy 2.0 中文文档(五十七)
29 0