ORM 查询指南

优质
小牛编辑
138浏览
2023-12-01

本节概述了使用SQLAlchemy ORM发出查询的方法 2.0 style 用法。

本节的读者应该熟悉 SQLAlchemy 1.4/2.0教程 ,特别是这里的大部分内容都是在 使用核心或ORM选择行 .

选择语句

SELECT语句由 select() 返回一个 Select 对象:

>>> from sqlalchemy import select
>>> stmt = select(User).where(User.name == 'spongebob')

调用 Select 通过ORM,它被传递到 Session.execute() ::

sql>>> result = session.execute(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
WHERE user_account.name = ?
[...] ('spongebob',)
>>> for user_obj in result.scalars():
...     print(f"{user_obj.name} {user_obj.fullname}")
spongebob Spongebob Squarepants

选择ORM实体和属性

这个 select() construct接受ORM实体,包括映射类以及表示映射列的类级属性,这些属性被转换为ORM注释 FromClauseColumnElement 施工时的构件。

A Select 包含ORM注释实体的对象通常使用 Session 对象,而不是 Connection 对象,以使与ORM相关的特性生效,包括返回ORM映射对象的实例。当使用 Connection 直接地说,结果行只包含列级别的数据。

下面我们从 User 实体,产生 Select 从映射的 Table 向哪个 User 已映射::

sql>>> result = session.execute(select(User).order_by(User.id))
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account ORDER BY user_account.id
[...] ()

从ORM实体中选择时,实体本身在结果中作为具有单个元素的行返回,而不是一系列单独的列;例如,上面的 Result 退货 Row 对象,这些对象每行只有一个元素,该元素保持在 User 对象::

>>> result.fetchone()
(User(id=1, name='spongebob', fullname='Spongebob Squarepants'),)

选择包含ORM实体的单元素行列表时,通常会跳过生成 Row 对象,而不是直接接收ORM实体,这是使用 Result.scalars() 方法:

>>> result.scalars().all()
[User(id=2, name='sandy', fullname='Sandy Cheeks'),
 User(id=3, name='patrick', fullname='Patrick Star'),
 User(id=4, name='squidward', fullname='Squidward Tentacles'),
 User(id=5, name='ehkrabs', fullname='Eugene H. Krabs')]

ORM实体在结果行中根据它们的类名命名,例如下面我们从两者中选择 UserAddress 同时:

>>> stmt = select(User, Address).join(User.addresses).order_by(User.id, Address.id)

sql>>> for row in session.execute(stmt):
...    print(f"{row.User.name} {row.Address.email_address}")
SELECT user_account.id, user_account.name, user_account.fullname,
address.id AS id_1, address.user_id, address.email_address
FROM user_account JOIN address ON user_account.id = address.user_id
ORDER BY user_account.id, address.id
[...] ()
spongebob spongebob@sqlalchemy.org
sandy sandy@sqlalchemy.org
sandy squirrel@squirrelpower.org
patrick pat999@aol.com
squidward stentcl@sqlalchemy.org

选择单个属性

映射类上的属性,例如 User.nameAddress.email_address ,具有与实体类本身类似的行为,例如 User 在传递给 select() . 它们的使用方式与表列的使用方式相同:

sql>>> result = session.execute(
...     select(User.name, Address.email_address).
...     join(User.addresses).
...     order_by(User.id, Address.id)
... )
SELECT user_account.name, address.email_address
FROM user_account JOIN address ON user_account.id = address.user_id
ORDER BY user_account.id, address.id
[...] ()

ORM属性,它们本身被称为 InstrumentedAttribute 对象,可以与任何 ColumnElement ,和以相同的方式在结果行中传递,例如下面我们在每行中按列名引用它们的值:

>>> for row in result:
...     print(f"{row.name}  {row.email_address}")
spongebob  spongebob@sqlalchemy.org
sandy  sandy@sqlalchemy.org
sandy  squirrel@squirrelpower.org
patrick  pat999@aol.com
squidward  stentcl@sqlalchemy.org

将选定的属性与绑定分组

这个 Bundle construct是一个可扩展的仅限ORM的构造,它允许将一组列表达式分组到结果行中:

>>> from sqlalchemy.orm import Bundle
>>> stmt = select(
...     Bundle("user", User.name, User.fullname),
...     Bundle("email", Address.email_address)
... ).join_from(User, Address)
sql>>> for row in session.execute(stmt):
...     print(f"{row.user.name} {row.email.email_address}")
SELECT user_account.name, user_account.fullname, address.email_address
FROM user_account JOIN address ON user_account.id = address.user_id
[...] ()
spongebob spongebob@sqlalchemy.org
sandy sandy@sqlalchemy.org
sandy squirrel@squirrelpower.org
patrick pat999@aol.com
squidward stentcl@sqlalchemy.org

这个 Bundle 对于创建轻量级视图以及自定义列分组(如映射)可能很有用。

参见

列束 -在ORM加载文档中。

选择ORM别名

如本教程所述 使用别名 ,可以使用 aliased() 针对映射类构造:

>>> from sqlalchemy.orm import aliased
>>> u1 = aliased(User)
>>> print(select(u1).order_by(u1.id))
SELECT user_account_1.id, user_account_1.name, user_account_1.fullname
FROM user_account AS user_account_1 ORDER BY user_account_1.id

当使用 Table.alias() ,SQL别名是匿名命名的。对于从具有显式名称的行中选择实体的情况 aliased.name 也可以传递参数::

>>> from sqlalchemy.orm import aliased
>>> u1 = aliased(User, name="u1")
>>> stmt = select(u1).order_by(u1.id)
sql>>> row = session.execute(stmt).first()
SELECT u1.id, u1.name, u1.fullname
FROM user_account AS u1 ORDER BY u1.id
[...] ()
>>> print(f"{row.u1.name}")
spongebob

这个 aliased 构造也是在ORM中使用子查询的核心;节 联接到子查询 进一步讨论。

从文本和核心语句获取ORM结果

ORM支持从来自其他源的SELECT语句加载实体。典型的用例是文本SELECT语句,在SQLAlchemy中,它使用 text() 构造。这个 text() construct一旦被构造,就可以使用语句将加载的ORM映射列的相关信息进行扩充;然后可以将这些信息与ORM实体本身相关联,以便基于该语句加载ORM对象。

给定一个文本SQL语句,我们希望从中加载:

>>> from sqlalchemy import text
>>> textual_sql = text("SELECT id, name, fullname FROM user_account ORDER BY id")

我们可以通过使用 TextClause.columns() 方法;当调用此方法时 TextClause 对象转换为 TextualSelect 对象,它承担的角色与 Select 构建。这个 TextClause.columns() 方法通常被传递 Column 对象或等效对象,在这种情况下,我们可以在 User 直接上课:

>>> textual_sql = textual_sql.columns(User.id, User.name, User.fullname)

我们现在有了一个ORM配置的SQL结构,可以分别加载“id”、“name”和“fullname”列。将此SELECT语句用作 User 相反,我们可以将这些列链接到启用了ORM的常规ORM Select 使用 Select.from_statement() 方法:

>>> # using from_statement()
>>> orm_sql = select(User).from_statement(textual_sql)
>>> for user_obj in session.execute(orm_sql).scalars():
...     print(user_obj)
SELECT id, name, fullname FROM user_account ORDER BY id
[...] ()
User(id=1, name='spongebob', fullname='Spongebob Squarepants')
User(id=2, name='sandy', fullname='Sandy Cheeks')
User(id=3, name='patrick', fullname='Patrick Star')
User(id=4, name='squidward', fullname='Squidward Tentacles')
User(id=5, name='ehkrabs', fullname='Eugene H. Krabs')

相同的 TextualSelect 对象也可以使用 TextualSelect.subquery() 方法,并链接到 User 使用 aliased() 按照下文中讨论的类似方式进行施工 联接到子查询 ::

>>> # using aliased() to select from a subquery
>>> orm_subquery = aliased(User, textual_sql.subquery())
>>> stmt = select(orm_subquery)
>>> for user_obj in session.execute(stmt).scalars():
...     print(user_obj)
SELECT anon_1.id, anon_1.name, anon_1.fullname
FROM (SELECT id, name, fullname FROM user_account ORDER BY id) AS anon_1
[...] ()
User(id=1, name='spongebob', fullname='Spongebob Squarepants')
User(id=2, name='sandy', fullname='Sandy Cheeks')
User(id=3, name='patrick', fullname='Patrick Star')
User(id=4, name='squidward', fullname='Squidward Tentacles')
User(id=5, name='ehkrabs', fullname='Eugene H. Krabs')

使用 TextualSelect 直接与 Select.from_statement() 与利用 aliased() 在前一种情况下,结果SQL中不生成子查询。从性能或复杂性的角度来看,这在某些情况下可能是有利的。

参见

使用INSERT、UPDATE和ON CONFLICATION(即upsert)返回ORM对象 -The Select.from_statement() 方法也适用于 DML 支持返回的语句。

联接

这个 Select.join()Select.join_from() 方法用于根据SELECT语句构造SQL联接。

本节将详细介绍这些方法的ORM用例。有关从核心角度对其使用的一般概述,请参阅 显式FROM子句和连接SQLAlchemy 1.4/2.0教程 .

用法 Select.join() 在ORM上下文中 2.0 style 查询与 Query.join() 方法在 1.x style 查询。

简单关系联接

考虑两个类之间的映射 UserAddress ,有关系 User.addresses 表示的集合 Address 与每个关联的对象 User . 最常见的用法是 Select.join() 是沿着此关系创建联接,使用 User.addresses 属性作为如何发生这种情况的指示器::

>>> stmt = select(User).join(User.addresses)

在上面的什么地方,呼叫 Select.join() 沿着 User.addresses 将导致SQL大约相当于:

>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account JOIN address ON user_account.id = address.user_id

在上面的例子中,我们提到 User.addresses 传到 Select.join() 作为“on子句”,也就是说,它指示连接的“on”部分应该如何构造。

链接多个连接

构造一个连接链,多个 Select.join() 可以使用呼叫。relationship-bound属性同时表示连接的左侧和右侧。考虑其他实体 OrderItem 那里 User.orders 关系是指 Order 实体,以及 Order.items 关系是指 Item 实体,通过关联表 order_items . 二 Select.join() 将加入来自第一个调用的结果 UserOrder ,还有一秒钟 OrderItem . 但是,自从 Order.items 是一个 many to many 关系中,它将生成两个单独的JOIN元素,结果SQL中总共有三个JOIN元素:

>>> stmt = (
...     select(User).
...     join(User.orders).
...     join(Order.items)
... )
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
JOIN user_order ON user_account.id = user_order.user_id
JOIN order_items AS order_items_1 ON user_order.id = order_items_1.order_id
JOIN item ON item.id = order_items_1.item_id

每次调用 Select.join() 方法的重要性仅限于我们希望从中连接的内容的“左”端需要在我们指示新目标之前出现在from列表中。 Select.join() 例如,如果我们指定 select(User).join(Order.items).join(User.orders) ,并将引发错误。在正确的实践中 Select.join() 方法的调用方式与我们希望如何呈现SQL中的JOIN子句一致,并且每个调用都应该表示与它前面的内容之间的清晰链接。

我们在FROM子句中目标的所有元素都可以作为继续从连接的潜在点。我们可以继续添加其他元素从 User 上面的实体,例如在 User.addresses 与我们的连接链的关系:

>>> stmt = (
...     select(User).
...     join(User.orders).
...     join(Order.items).
...     join(User.addresses)
... )
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
JOIN user_order ON user_account.id = user_order.user_id
JOIN order_items AS order_items_1 ON user_order.id = order_items_1.order_id
JOIN item ON item.id = order_items_1.item_id
JOIN address ON user_account.id = address.user_id

联接到目标实体或可选

第二种形式 Select.join() 允许将任何映射实体或核心可选构造作为目标。在这种用法中, Select.join() 会尝试 推断 JOIN的ON子句,使用两个实体之间的自然外键关系:

>>> stmt = select(User).join(Address)
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account JOIN address ON user_account.id = address.user_id

在上面的通话表中, Select.join() 被要求自动推断“on子句”。如果没有,则此调用窗体最终将引发一个错误 ForeignKeyConstraint 两者之间的设置映射 Table 如果有多个 ForeignKeyConstraint 它们之间的界限使得要使用的适当约束是不明确的。

注解

当利用 Select.join()Select.join_from() 在不指示ON子句的情况下,配置了ORM relationship() 构造是 不考虑在内 . 仅配置 ForeignKeyConstraint 映射级别的实体之间的关系 Table 当试图为联接推断ON子句时,将查询对象。

用ON子句联接到目标

第三个调用形式允许显式传递目标实体和ON子句。包含SQL表达式作为ON子句的示例如下:

>>> stmt = select(User).join(Address, User.id==Address.user_id)
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account JOIN address ON user_account.id = address.user_id

基于子句的表达式也可以是关系绑定属性;此形式实际上声明 Address 两次,但这是可以接受的:

>>> stmt = select(User).join(Address, User.addresses)
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account JOIN address ON user_account.id = address.user_id

如果我们在别名实体中使用上述语法,那么它的功能就更强大了。的默认目标 User.addressesAddress 类,但是如果我们使用 aliased() , the aliased() 表单将用作目标,如下例所示:

>>> a1 = aliased(Address)
>>> a2 = aliased(Address)
>>> stmt = (
...     select(User).
...     join(a1, User.addresses).
...     join(a2, User.addresses).
...     where(a1.email_address == 'ed@foo.com').
...     where(a2.email_address == 'ed@bar.com')
... )
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
JOIN address AS address_1 ON user_account.id = address_1.user_id
JOIN address AS address_2 ON user_account.id = address_2.user_id
WHERE address_1.email_address = :email_address_1
AND address_2.email_address = :email_address_2

使用关系绑定属性时,还可以使用别名实体替换目标实体 PropComparator.of_type() 方法。使用此方法的相同示例为:

>>> stmt = (
...     select(User).
...     join(User.addresses.of_type(a1)).
...     join(User.addresses.of_type(a2)).
...     where(a1.email_address == 'ed@foo.com').
...     where(a2.email_address == 'ed@bar.com')
... )
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
JOIN address AS address_1 ON user_account.id = address_1.user_id
JOIN address AS address_2 ON user_account.id = address_2.user_id
WHERE address_1.email_address = :email_address_1
AND address_2.email_address = :email_address_2

扩充内置ON子句

作为在现有关系条件下提供完整定制的替代品 PropComparator.and_() 函数可以应用于relationship属性以将附加条件扩充到ON子句中;附加条件将使用AND与默认条件组合。下面,ON标准介于 user_accountaddress 包含由连接的两个独立元素 AND ,第一个是沿着外键的自然连接,第二个是自定义限制条件:

>>> stmt = (
...     select(User).
...     join(User.addresses.and_(Address.email_address != 'foo@bar.com'))
... )
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
JOIN address ON user_account.id = address.user_id
AND address.email_address != :email_address_1

参见

这个 PropComparator.and_() 方法也适用于装入器策略。参见章节 向加载程序选项添加条件 举个例子。

联接到子查询

连接的目标可以是任何“可选”的实体,其中有效地包括子单元。使用ORM时,这些目标通常是用 aliased() 构造,但这不是严格要求的,尤其是在结果中未返回联接实体时。例如,从 User 实体到 Address 实体,其中 Address 实体表示为行限制的子查询,我们首先构造一个 Subquery 对象使用 Select.subquery() ,然后可以将其用作 Select.join() 方法:

>>> subq = (
...     select(Address).
...     where(Address.email_address == 'pat999@aol.com').
...     subquery()
... )
>>> stmt = select(User).join(subq, User.id == subq.c.user_id)
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
JOIN (SELECT address.id AS id,
address.user_id AS user_id, address.email_address AS email_address
FROM address
WHERE address.email_address = :email_address_1) AS anon_1
ON user_account.id = anon_1.user_id

当通过调用时,上面的SELECT语句 Session.execute() 将返回包含 User 实体,但不是 Address 实体。为了增加 Address 实体到将在结果集中返回的实体集,我们构造一个 aliased() 反对 Address 实体和自定义子查询。注意,我们还应用了一个名称 "address"aliased() 构造,以便在结果行中按名称引用它:

>>> address_subq = aliased(Address, subq, name="address")
>>> stmt = select(User, address_subq).join(address_subq)
>>> for row in session.execute(stmt):
...     print(f"{row.User} {row.address}")
SELECT user_account.id, user_account.name, user_account.fullname,
anon_1.id AS id_1, anon_1.user_id, anon_1.email_address
FROM user_account
JOIN (SELECT address.id AS id,
address.user_id AS user_id, address.email_address AS email_address
FROM address
WHERE address.email_address = ?) AS anon_1 ON user_account.id = anon_1.user_id
[...] ('pat999@aol.com',)
User(id=3, name='patrick', fullname='Patrick Star') Address(id=4, email_address='pat999@aol.com')

对于表示多个实体的子查询,同一个子查询也可以由多个实体引用。子查询本身在语句中将保持唯一,而链接到它的实体使用 aliased 参考不同的列集合:

>>> user_address_subq = (
...        select(User.id, User.name, Address.id, Address.email_address).
...        join_from(User, Address).
...        where(Address.email_address.in_(['pat999@aol.com', 'squirrel@squirrelpower.org'])).
...        subquery()
... )
>>> user_alias = aliased(User, user_address_subq, name="user")
>>> address_alias = aliased(Address, user_address_subq, name="address")
>>> stmt = select(user_alias, address_alias).where(user_alias.name == 'sandy')
>>> for row in session.execute(stmt):
...     print(f"{row.user} {row.address}")
SELECT anon_1.id, anon_1.name, anon_1.id_1, anon_1.email_address
FROM (SELECT user_account.id AS id, user_account.name AS name, address.id AS id_1, address.email_address AS email_address
FROM user_account JOIN address ON user_account.id = address.user_id
WHERE address.email_address IN (?, ?)) AS anon_1
WHERE anon_1.name = ?
[...] ('pat999@aol.com', 'squirrel@squirrelpower.org', 'sandy')
User(id=2, name='sandy', fullname='Sandy Cheeks') Address(id=3, email_address='squirrel@squirrelpower.org')

控制加入内容

如果当前状态的左侧 Select 不符合我们想加入的目标 Select.join_from() 可使用的方法:

>>> stmt = select(Address).join_from(User, User.addresses).where(User.name == 'sandy')
>>> print(stmt)
SELECT address.id, address.user_id, address.email_address
FROM user_account JOIN address ON user_account.id = address.user_id
WHERE user_account.name = :name_1

这个 Select.join_from() 方法接受两个或三个参数,格式为 <join from>, <onclause><join from>, <join to>, [<onclause>] ::

>>> stmt = select(Address).join_from(User, Address).where(User.name == 'sandy')
>>> print(stmt)
SELECT address.id, address.user_id, address.email_address
FROM user_account JOIN address ON user_account.id = address.user_id
WHERE user_account.name = :name_1

为SELECT设置初始FROM子句,以便 Select.join() 可以在以后使用 Select.select_from() 也可以使用以下方法:

>>> stmt = select(Address).select_from(User).join(Address).where(User.name == 'sandy')
>>> print(stmt)
SELECT address.id, address.user_id, address.email_address
FROM user_account JOIN address ON user_account.id = address.user_id
WHERE user_account.name = :name_1

小技巧

这个 Select.select_from() 方法实际上并不对FROM子句中表的顺序拥有最终决定权。如果该语句还引用 Join 构造,该构造以不同的顺序引用现有表,则 Join 构造优先。当我们使用像这样的方法时 Select.join()Select.join_from() ,这些方法最终会创建这样一个 Join 对象。因此我们可以看到 Select.select_from() 在类似以下情况下被覆盖::

>>> stmt = select(Address).select_from(User).join(Address.user).where(User.name == 'sandy')
>>> print(stmt)
SELECT address.id, address.user_id, address.email_address
FROM address JOIN user_account ON user_account.id = address.user_id
WHERE user_account.name = :name_1

在上面的位置,我们看到FROM子句是 address JOIN user_account ,即使我们声明 select_from(User) 第一。因为 .join(Address.user) 方法调用时,该语句最终等同于以下内容:

>>> user_table = User.__table__
>>> address_table = Address.__table__
>>> from sqlalchemy.sql import join
>>>
>>> j = address_table.join(user_table, user_table.c.id == address_table.c.user_id)
>>> stmt = (
...     select(address_table).select_from(user_table).select_from(j).
...     where(user_table.c.name == 'sandy')
... )
>>> print(stmt)
SELECT address.id, address.user_id, address.email_address
FROM address JOIN user_account ON user_account.id = address.user_id
WHERE user_account.name = :name_1

这个 Join 构造作为另一个条目添加到 Select.select_from() 取代上一条目的列表。

特殊关系运算符

详见 SQLAlchemy 1.4/2.0教程在查询中使用关系 ,ORM属性映射 relationship() 可以以多种方式用作SQL构造助手。除上述文件外 联接 ,关系也可能生成要在WHERE子句中使用的条件。请参阅下面的链接部分。

参见

中的节 使用相关对象 剖面图 SQLAlchemy 1.4/2.0教程

ORM加载程序选项

加载程序选项是传递给 Select.options() 方法,该方法同时影响列和面向关系的属性的加载。大多数装载机选项从 Load 等级制度。有关使用加载程序选项的完整概述,请参阅下面的链接部分。

参见

  • 加载柱 -详细说明映射器和加载选项,这些选项会影响列和SQL表达式映射属性的加载方式

  • 关系加载技术 -详细说明关系和加载选项如何影响 relationship() 已加载映射属性

ORM执行选项

执行选项是传递给“执行选项”方法的关键字参数,它发生在语句执行级别。主要的“执行选项”方法位于 Connection.execution_options() . 在ORM中,执行选项也可以传递给 Session.execute() 使用 Session.execute.execution_options 参数。也许更简洁地说,大多数执行选项,包括那些特定于ORM的选项,都可以使用 Executable.execution_options() 方法,以便选项可以直接与语句关联,而不是单独配置。以下示例将使用此表单。

填充现有

这个 populate_existing execution选项确保对于加载的所有行 Session 将完全刷新,删除对象中的任何现有数据(包括挂起的更改),并替换为从结果加载的数据。

示例用法如下:

>>> stmt = select(User).execution_options(populate_existing=True)
sql>>> result = session.execute(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
...

通常,ORM对象只加载一次,如果它们与后续结果行中的主键匹配,则该行不会应用于该对象。这既可以保留对象上挂起的、未刷新的更改,也可以避免刷新已存在的数据的开销和复杂性。这个 Session 假设一个高度隔离的事务的默认工作模型,并且如果数据预期在事务内部发生变化,那么这些用例将使用显式的步骤(如此方法)进行处理。

使用 populate_existing ,可以刷新与查询匹配的任何对象集,并且还允许控制关系加载器选项。例如,要在刷新实例的同时刷新相关的一组对象,请执行以下操作:

stmt = (
    select(User).
    where(User.name.in_(names)).
    execution_options(populate_existing=True).
    options(selectinload(User.addresses)
)
# will refresh all matching User objects as well as the related
# Address objects
users = session.execute(stmt).scalars().all()

另一个用例 populate_existing 支持各种属性加载功能,这些特性可以更改每个查询加载属性的方式。适用的选项包括:

这个 populate_existing 执行选项等同于 Query.populate_existing() 方法在 1.x style ORM查询。

参见

我正在用会话加载数据,但没有看到我在其他地方所做的更改。 - in 常见问题

刷新/过期 -在ORM中 Session 文档

自动冲洗

此选项传递为 False 将导致 Session 不调用“自动刷新”步骤。相当于使用 Session.no_autoflush 要禁用自动刷新的上下文管理器:

>>> stmt = select(User).execution_options(autoflush=False)
sql>>> session.execute(stmt)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
...

此选项也适用于启用ORM的情况 UpdateDelete 查询。

这个 autoflush 执行选项等同于 Query.autoflush() 方法在 1.x style ORM查询。

参见

冲洗

单位产量

这个 yield_per 执行选项是一个整数值,它将导致 Result 一次只产生固定数量的行。它通常与结果分区方法一起使用,例如 Result.partitions() ,例如:

>>> stmt = select(User).execution_options(yield_per=10)
sql>>> for partition in session.execute(stmt).partitions(10):
...     for row in partition:
...         print(row)
SELECT user_account.id, user_account.name, user_account.fullname
FROM user_account
[...] ()
(User(id=1, name='spongebob', fullname='Spongebob Squarepants'),)
...

此方法的目的是在获取非常大的结果集(>10000行)时,对子集合中的结果进行批处理并部分生成结果,这样Python解释器就不需要声明非常大的内存区域,这既耗时又会导致内存使用过度。当使用适当的每次设置的收益率(例如大约1000)时,提取数十万行的性能通常会加倍,即使DBAPIS缓冲行(最多)。

什么时候? yield_per 被使用了 Connection.execution_options.stream_results 还为核心执行设置了选项,以便在后端支持流式处理/服务器端游标时使用它 1

这个 yield_per 执行选项 使用集合时与subqueryload紧急加载或joinedload紧急加载不兼容 . 它可能与selectinload eager loading兼容, 如果数据库驱动程序支持多个独立的游标 2 .

此外, yield_per 执行选项与 Result.unique() 由于此方法依赖于存储所有行的完整标识集,因此它必然会违背使用 yield_per 这是为了处理任意数量的行。

在 1.4.6 版更改: 对象读取ORM行时引发异常 Result 对象,该对象利用 Result.unique() 过滤的同时, yield_per 使用执行选项。

这个 yield_per 执行选项等同于 Query.yield_per() 方法在 1.x style ORM查询。

1

目前已知的 psycopg2mysqldbpymysql . 其他后端将预缓冲所有行。原始数据库行的内存使用量远小于ORM映射对象的内存使用量,但在进行基准测试时仍应将其考虑在内。

2

这个 psycopg2pysqlite 已知驱动程序可以工作,但MySQL和SQL Server ODBC驱动程序不工作。

参见

使用服务器端游标(即流结果)

使用任意WHERE子句更新/删除

这个 Session.execute() 方法,除了处理启用的ORM Select 对象,也可以容纳启用了ORM的 UpdateDelete 对象,它更新或删除任意数量的数据库行,同时还能够同步中本地存在的匹配对象的状态 Session . 参见章节 使用任意WHERE子句更新和删除 关于这个功能的背景。