SQLAlchemy 2.0 文档
SQLAlchemy ORM
- ORM 快速入门
- ORM 映射类配置
- 关系配置
- ORM 查询指南
- 为 ORM 映射类编写 SELECT 语句
- 为继承映射编写 SELECT 语句
- 启用 ORM 的 INSERT、UPDATE 和 DELETE 语句
- 列加载选项
- 关系加载技术¶
- 关系加载样式摘要
- 在映射时配置加载器策略
- 使用加载器选项进行关系加载
- 延迟加载
- 连接迫切加载
- Select IN 加载
- 子查询迫切加载
- 使用哪种加载方式?
- 多态迫切加载
- 通配符加载策略
- 将显式连接/语句路由到迫切加载的集合中
- 关系加载器 API
contains_eager()
defaultload()
immediateload()
joinedload()
lazyload()
Load
Load.contains_eager()
Load.defaultload()
Load.defer()
Load.get_children()
Load.immediateload()
Load.inherit_cache
Load.joinedload()
Load.lazyload()
Load.load_only()
Load.noload()
Load.options()
Load.process_compile_state()
Load.process_compile_state_replaced_entities()
Load.propagate_to_loaders
Load.raiseload()
Load.selectin_polymorphic()
Load.selectinload()
Load.subqueryload()
Load.undefer()
Load.undefer_group()
Load.with_expression()
noload()
raiseload()
selectinload()
subqueryload()
- 用于查询的 ORM API 特性
- 旧版 Query API
- 使用 Session
- 事件和内部机制
- ORM 扩展
- ORM 示例
项目版本
- 上一篇: 列加载选项
- 下一篇: 用于查询的 ORM API 特性
- 向上: 首页
- 本页内容
- 关系加载技术
- 关系加载样式摘要
- 在映射时配置加载器策略
- 使用加载器选项进行关系加载
- 延迟加载
- 连接迫切加载
- Select IN 加载
- 子查询迫切加载
- 使用哪种加载方式?
- 多态迫切加载
- 通配符加载策略
- 将显式连接/语句路由到迫切加载的集合中
- 关系加载器 API
contains_eager()
defaultload()
immediateload()
joinedload()
lazyload()
Load
Load.contains_eager()
Load.defaultload()
Load.defer()
Load.get_children()
Load.immediateload()
Load.inherit_cache
Load.joinedload()
Load.lazyload()
Load.load_only()
Load.noload()
Load.options()
Load.process_compile_state()
Load.process_compile_state_replaced_entities()
Load.propagate_to_loaders
Load.raiseload()
Load.selectin_polymorphic()
Load.selectinload()
Load.subqueryload()
Load.undefer()
Load.undefer_group()
Load.with_expression()
noload()
raiseload()
selectinload()
subqueryload()
关系加载技术¶
SQLAlchemy 的一大特点是提供了广泛的控制,以控制在查询时如何加载相关对象。“相关对象” 是指使用 relationship()
在映射器上配置的集合或标量关联。此行为可以在映射器构建时使用 relationship.lazy
参数配置,也可以通过将 ORM 加载器选项 与 Select
构造结合使用。
关系的加载分为三类:延迟加载、迫切加载和无加载。延迟加载是指从查询返回对象,但最初未加载相关对象。当首次访问特定对象上的给定集合或引用时,会发出额外的 SELECT 语句,以便加载请求的集合。
迫切加载是指从查询返回对象,并且已预先加载了相关的集合或标量引用。ORM 通过以下方式实现此目的:要么使用 JOIN 增强通常发出的 SELECT 语句以同时加载相关行,要么在主语句之后发出额外的 SELECT 语句以一次加载集合或标量引用。
“无”加载是指禁用给定关系的加载,要么属性为空且永远不会加载,要么在访问时引发错误,以防止意外的延迟加载。
关系加载样式摘要¶
关系加载的主要形式是
延迟加载 - 通过
lazy='select'
或lazyload()
选项可用,这种加载形式在属性访问时发出 SELECT 语句,以延迟加载单个对象上的相关引用。延迟加载是所有relationship()
构造的 默认加载样式,除非另有说明relationship.lazy
选项。延迟加载的详细信息请参见 延迟加载。Select IN 加载 - 通过
lazy='selectin'
或selectinload()
选项可用,这种加载形式发出第二个(或更多)SELECT 语句,该语句将父对象的主键标识符组装到 IN 子句中,以便通过主键一次加载相关集合/标量引用的所有成员。Select IN 加载的详细信息请参见 Select IN 加载。连接加载 - 通过
lazy='joined'
或joinedload()
选项可用,这种加载形式将 JOIN 应用于给定的 SELECT 语句,以便在同一结果集中加载相关行。连接迫切加载的详细信息请参见 连接迫切加载。引发加载 - 通过
lazy='raise'
、lazy='raise_on_sql'
或raiseload()
选项可用,这种加载形式在通常会发生延迟加载的同一时间触发,但它会引发 ORM 异常,以防止应用程序进行意外的延迟加载。引发加载的介绍请参见 使用 raiseload 防止意外的延迟加载。子查询加载 - 通过
lazy='subquery'
或subqueryload()
选项可用,这种加载形式发出第二个 SELECT 语句,该语句重新声明嵌入在子查询内部的原始查询,然后将该子查询连接到要加载的相关表,以一次加载相关集合/标量引用的所有成员。子查询迫切加载的详细信息请参见 子查询迫切加载。只写加载 - 通过
lazy='write_only'
可用,或通过使用WriteOnlyMapped
注解来注解Relationship
对象的左侧。这种仅限集合的加载器样式生成了一种替代属性工具,它永远不会隐式地从数据库加载记录,而是只允许WriteOnlyCollection.add()
、WriteOnlyCollection.add_all()
和WriteOnlyCollection.remove()
方法。通过调用使用WriteOnlyCollection.select()
方法构造的 SELECT 语句来执行集合的查询。只写加载将在 只写关系 中讨论。动态加载 - 通过
lazy='dynamic'
可用,或通过使用DynamicMapped
注解来注解Relationship
对象的左侧。这是一种旧版的仅限集合的加载器样式,它在访问集合时生成Query
对象,从而允许针对集合的内容发出自定义 SQL。但是,动态加载器会在各种情况下隐式迭代底层集合,这使得它们不太适合管理真正的大型集合。动态加载器已被 “只写” 集合取代,后者将防止在任何情况下隐式加载底层集合。动态加载器将在 动态关系加载器 中讨论。
在映射时配置加载器策略¶
可以配置特定关系的加载器策略,以便在加载映射类型的对象的所有情况下发生,而没有任何修改它的查询级别选项。这是使用 relationship.lazy
参数在 relationship()
中配置的;此参数的常用值包括 select
、selectin
和 joined
。
下面的示例说明了 一对多 中的关系示例,配置 Parent.children
关系在使用 Parent
对象发出 SELECT 语句时使用 Select IN 加载
from typing import List
from sqlalchemy import ForeignKey
from sqlalchemy.orm import DeclarativeBase
from sqlalchemy.orm import Mapped
from sqlalchemy.orm import mapped_column
from sqlalchemy.orm import relationship
class Base(DeclarativeBase):
pass
class Parent(Base):
__tablename__ = "parent"
id: Mapped[int] = mapped_column(primary_key=True)
children: Mapped[List["Child"]] = relationship(lazy="selectin")
class Child(Base):
__tablename__ = "child"
id: Mapped[int] = mapped_column(primary_key=True)
parent_id: Mapped[int] = mapped_column(ForeignKey("parent.id"))
上面,每当加载 Parent
对象的集合时,每个 Parent
也将填充其 children
集合,使用发出第二个查询的 "selectin"
加载器策略。
relationship.lazy
参数的默认值为 "select"
,它表示 延迟加载。
使用加载器选项进行关系加载¶
配置加载策略的另一种可能更常见的方法是在每个查询的基础上针对特定属性使用 Select.options()
方法设置它们。使用加载器选项可以对关系加载进行非常详细的控制;最常见的是 joinedload()
、selectinload()
和 lazyload()
。该选项接受一个类绑定的属性,该属性引用应作为目标的特定类/属性
from sqlalchemy import select
from sqlalchemy.orm import lazyload
# set children to load lazily
stmt = select(Parent).options(lazyload(Parent.children))
from sqlalchemy.orm import joinedload
# set children to load eagerly with a join
stmt = select(Parent).options(joinedload(Parent.children))
加载器选项也可以使用 方法链 进行“链接”,以指定应如何发生更深层次的加载
from sqlalchemy import select
from sqlalchemy.orm import joinedload
stmt = select(Parent).options(
joinedload(Parent.children).subqueryload(Child.subelements)
)
链式加载器选项可以应用于“延迟”加载的集合。这意味着当集合或关联在访问时被延迟加载时,指定的选项将生效
from sqlalchemy import select
from sqlalchemy.orm import lazyload
stmt = select(Parent).options(lazyload(Parent.children).subqueryload(Child.subelements))
上面,查询将返回 Parent
对象,而未加载 children
集合。当首次访问特定 Parent
对象上的 children
集合时,它将延迟加载相关对象,但还会对 children
的每个成员上的 subelements
集合应用迫切加载。
向加载器选项添加条件¶
用于指示加载器选项的关系属性包括向创建的连接的 ON 子句或所涉及的 WHERE 条件添加其他过滤条件的能力,具体取决于加载器策略。这可以使用 PropComparator.and_()
方法来实现,该方法将传递一个选项,以便加载的结果仅限于给定的过滤条件
from sqlalchemy import select
from sqlalchemy.orm import lazyload
stmt = select(A).options(lazyload(A.bs.and_(B.id > 5)))
当使用限制条件时,如果已加载特定集合,则不会刷新它;为了确保新条件生效,请应用 填充现有 执行选项
from sqlalchemy import select
from sqlalchemy.orm import lazyload
stmt = (
select(A)
.options(lazyload(A.bs.and_(B.id > 5)))
.execution_options(populate_existing=True)
)
为了将过滤条件添加到整个查询中实体的所有出现,而不管加载器策略或它在加载过程中出现的位置如何,请参阅 with_loader_criteria()
函数。
1.4 版本新增。
使用 Load.options() 指定子选项¶
使用方法链,显式声明路径中每个链接的加载器样式。要在路径中导航而不更改特定属性的现有加载器样式,可以使用 defaultload()
方法/函数
from sqlalchemy import select
from sqlalchemy.orm import defaultload
stmt = select(A).options(defaultload(A.atob).joinedload(B.btoc))
可以使用类似的方法一次指定多个子选项,使用 Load.options()
方法
from sqlalchemy import select
from sqlalchemy.orm import defaultload
from sqlalchemy.orm import joinedload
stmt = select(A).options(
defaultload(A.atob).options(joinedload(B.btoc), joinedload(B.btod))
)
另请参阅
在相关对象和集合上使用 load_only() - 说明了组合关系和面向列的加载器选项的示例。
注意
应用于对象的延迟加载集合的加载器选项对特定对象实例是 “粘性的”,这意味着只要它们存在于内存中,它们就会在由该特定对象加载的集合上持续存在。例如,给定之前的示例
stmt = select(Parent).options(lazyload(Parent.children).subqueryload(Child.subelements))
如果由上述查询加载的特定 Parent
对象上的 children
集合已过期(例如,当 Session
对象的事务已提交或回滚,或者使用了 Session.expire_all()
时),当下次访问 Parent.children
集合以重新加载它时,Child.subelements
集合将再次使用子查询迫切加载进行加载。即使从随后的查询中访问上述 Parent
对象,该查询指定了一组不同的选项,情况仍然如此。要在不清除和重新加载现有对象的情况下更改其选项,必须结合使用 填充现有 执行选项显式设置它们
# change the options on Parent objects that were already loaded
stmt = (
select(Parent)
.execution_options(populate_existing=True)
.options(lazyload(Parent.children).lazyload(Child.subelements))
.all()
)
如果上面加载的对象已完全从 Session
中清除,例如由于垃圾回收或使用了 Session.expunge_all()
,则 “粘性” 选项也将消失,如果再次加载,新创建的对象将使用新选项。
未来的 SQLAlchemy 版本可能会添加更多用于操作已加载对象上的加载器选项的替代方案。
延迟加载¶
默认情况下,所有对象间关系都是 延迟加载。relationship()
关联的标量或集合属性包含一个触发器,该触发器在首次访问该属性时触发。此触发器通常在访问点发出 SQL 调用,以便加载相关对象或对象
>>> spongebob.addresses
SELECT
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses
WHERE ? = addresses.user_id
[5]
[<Address(u'spongebob@google.com')>, <Address(u'j25@yahoo.com')>]
不发出 SQL 的一种情况是对于简单的多对一关系,当相关对象可以通过其主键单独识别并且该对象已存在于当前 Session
中时。因此,虽然延迟加载对于相关集合来说可能很昂贵,但在加载大量具有针对相对较小的一组可能目标对象的简单多对一关系的对象的情况下,延迟加载可能能够在本地引用这些对象,而无需发出与父对象一样多的 SELECT 语句。
这种 “在属性访问时加载” 的默认行为被称为 “延迟” 或 “select” 加载 - 名称 “select” 是因为在首次访问属性时通常会发出 “SELECT” 语句。
可以使用 lazyload()
加载器选项为通常以其他方式配置的给定属性启用延迟加载
from sqlalchemy import select
from sqlalchemy.orm import lazyload
# force lazy loading for an attribute that is set to
# load some other way normally
stmt = select(User).options(lazyload(User.addresses))
使用 raiseload 防止意外的延迟加载¶
lazyload()
策略产生一种效果,这是对象关系映射中最常被提及的问题之一;N+1 问题,它指出对于任何加载的 N 个对象,访问其延迟加载的属性意味着将发出 N+1 个 SELECT 语句。在 SQLAlchemy 中,缓解 N+1 问题的常用方法是利用其功能强大的迫切加载系统。但是,迫切加载要求预先使用 Select
指定要加载的属性。代码可能访问未迫切加载的其他属性的问题(不希望延迟加载)可以使用 raiseload()
策略来解决;此加载器策略将延迟加载的行为替换为引发信息性错误
from sqlalchemy import select
from sqlalchemy.orm import raiseload
stmt = select(User).options(raiseload(User.addresses))
上面,从上述查询加载的 User
对象将不会加载 .addresses
集合;如果稍后某些代码尝试访问此属性,则会引发 ORM 异常。
raiseload()
可以与所谓的 “通配符” 说明符一起使用,以指示所有关系都应使用此策略。例如,要将仅一个属性设置为迫切加载,而将其余所有属性设置为引发
from sqlalchemy import select
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import raiseload
stmt = select(Order).options(joinedload(Order.items), raiseload("*"))
上面的通配符将应用于 所有 关系,而不仅仅是 Order
上的关系(除了 items
之外),还包括 Item
对象上的所有关系。要仅为 Order
对象设置 raiseload()
,请使用 Load
指定完整路径
from sqlalchemy import select
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import Load
stmt = select(Order).options(joinedload(Order.items), Load(Order).raiseload("*"))
相反,要仅为 Item
对象设置引发
stmt = select(Order).options(joinedload(Order.items).raiseload("*"))
raiseload()
选项仅适用于关系属性。对于面向列的属性,defer()
选项支持 defer.raiseload
选项,其工作方式相同。
提示
“raiseload” 策略 不适用 于 工作单元 刷新过程中。这意味着,如果 Session.flush()
过程需要加载集合才能完成其工作,它将在绕过任何 raiseload()
指令的情况下执行此操作。
连接迫切加载¶
连接迫切加载是 SQLAlchemy ORM 中包含的最早的迫切加载样式。它通过将 JOIN(默认为 LEFT OUTER join)连接到发出的 SELECT 语句来工作,并从与父级相同的结果集中填充目标标量/集合。
在映射级别,它看起来像这样
class Address(Base):
# ...
user: Mapped[User] = relationship(lazy="joined")
连接迫切加载通常作为查询的选项应用,而不是作为映射上的默认加载选项,尤其是在用于集合而不是多对一引用时。这是通过使用 joinedload()
加载器选项实现的
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import joinedload
>>> stmt = select(User).options(joinedload(User.addresses)).filter_by(name="spongebob")
>>> spongebob = session.scalars(stmt).unique().all()
SELECT
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
LEFT OUTER JOIN addresses AS addresses_1
ON users.id = addresses_1.user_id
WHERE users.name = ?
['spongebob']
提示
当包含对一对多或多对多集合的引用 joinedload()
时,必须将 Result.unique()
方法应用于返回的结果,这将通过主键对传入的行进行唯一化,否则这些行会被连接倍增。如果不存在,ORM 将引发错误。
在现代 SQLAlchemy 中,这并非自动行为,因为它会更改结果集的行为,使其返回的对象数量少于语句通常返回的行数。因此,SQLAlchemy 显式地保留了 Result.unique()
的使用,这样就不会对返回的对象是根据主键进行唯一化处理产生歧义。
默认情况下,发出的 JOIN 是 LEFT OUTER JOIN,以允许前导对象不引用相关行。对于保证具有元素的属性,例如多对一引用到相关对象,且引用的外键为 NOT NULL,则可以使用 inner join 使查询更有效率;这可以通过映射级别的 relationship.innerjoin
标志来实现
class Address(Base):
# ...
user_id: Mapped[int] = mapped_column(ForeignKey("users.id"))
user: Mapped[User] = relationship(lazy="joined", innerjoin=True)
在查询选项级别,通过 joinedload.innerjoin
标志
from sqlalchemy import select
from sqlalchemy.orm import joinedload
stmt = select(Address).options(joinedload(Address.user, innerjoin=True))
当 JOIN 应用于包含 OUTER JOIN 的链中时,它将自身向右嵌套
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import joinedload
>>> stmt = select(User).options(
... joinedload(User.addresses).joinedload(Address.widgets, innerjoin=True)
... )
>>> results = session.scalars(stmt).unique().all()
SELECT
widgets_1.id AS widgets_1_id,
widgets_1.name AS widgets_1_name,
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
LEFT OUTER JOIN (
addresses AS addresses_1 JOIN widgets AS widgets_1 ON
addresses_1.widget_id = widgets_1.id
) ON users.id = addresses_1.user_id
提示
如果在发出 SELECT 时使用数据库行锁定技术,即使用 Select.with_for_update()
方法来发出 SELECT..FOR UPDATE,则连接的表也可能被锁定,这取决于所用后端的行为。因此,不建议同时使用连接迫切加载和 SELECT..FOR UPDATE。
连接迫切加载的禅意¶
由于连接迫切加载似乎与 Select.join()
的使用有很多相似之处,因此经常会让人困惑何时以及如何使用它。至关重要的是要理解,虽然 Select.join()
用于更改查询的结果,但 joinedload()
会尽力不更改查询的结果,而是隐藏渲染的 join 的效果,仅允许相关对象存在。
加载器策略背后的理念是,任何加载方案集都可以应用于特定的查询,并且结果不会改变 - 只有完全加载相关对象和集合所需的 SQL 语句数量会改变。一个特定的查询可能一开始使用所有延迟加载。在上下文中使用了它之后,可能会发现总是会访问特定的属性或集合,并且更改这些属性或集合的加载器策略会更有效率。可以更改策略,而无需对查询进行其他修改,结果将保持不变,但会发出更少的 SQL 语句。理论上(并且几乎在实践中),您对 Select
所做的任何操作都不会使其基于加载器策略的更改而加载不同组的主对象或相关对象。
joinedload()
特别是如何实现不影响返回的实体行的结果的呢?它会创建其添加到查询中的 join 的匿名别名,以便查询的其他部分无法引用它们。例如,下面的查询使用 joinedload()
从 users
创建到 addresses
的 LEFT OUTER JOIN,但是针对 Address.email_address
添加的 ORDER BY
是无效的 - Address
实体在查询中未命名
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import joinedload
>>> stmt = (
... select(User)
... .options(joinedload(User.addresses))
... .filter(User.name == "spongebob")
... .order_by(Address.email_address)
... )
>>> result = session.scalars(stmt).unique().all()
SELECT
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
LEFT OUTER JOIN addresses AS addresses_1
ON users.id = addresses_1.user_id
WHERE users.name = ?
ORDER BY addresses.email_address <-- this part is wrong !
['spongebob']
在上面,ORDER BY addresses.email_address
是无效的,因为 addresses
不在 FROM 列表中。加载 User
记录并按电子邮件地址排序的正确方法是使用 Select.join()
>>> from sqlalchemy import select
>>> stmt = (
... select(User)
... .join(User.addresses)
... .filter(User.name == "spongebob")
... .order_by(Address.email_address)
... )
>>> result = session.scalars(stmt).unique().all()
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
JOIN addresses ON users.id = addresses.user_id
WHERE users.name = ?
ORDER BY addresses.email_address
['spongebob']
上面的语句当然与之前的语句不同,因为 addresses
中的列根本不包含在结果中。我们可以重新添加 joinedload()
,这样就有两个 join - 一个是我们正在排序的 join,另一个是匿名使用的 join,用于加载 User.addresses
集合的内容
>>> stmt = (
... select(User)
... .join(User.addresses)
... .options(joinedload(User.addresses))
... .filter(User.name == "spongebob")
... .order_by(Address.email_address)
... )
>>> result = session.scalars(stmt).unique().all()
SELECT
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users JOIN addresses
ON users.id = addresses.user_id
LEFT OUTER JOIN addresses AS addresses_1
ON users.id = addresses_1.user_id
WHERE users.name = ?
ORDER BY addresses.email_address
['spongebob']
我们在上面看到的是,我们使用 Select.join()
是为了提供我们希望在后续查询条件中使用的 JOIN 子句,而我们使用 joinedload()
只关注加载结果中每个 User
的 User.addresses
集合。在这种情况下,这两个 join 很可能显得多余 - 确实如此。如果我们只想使用一个 JOIN 来进行集合加载和排序,我们使用 contains_eager()
选项,如下面的 将显式 Join/语句路由到迫切加载的集合中 中所述。但是要了解 joinedload()
的作用,请考虑如果我们过滤特定的 Address
>>> stmt = (
... select(User)
... .join(User.addresses)
... .options(joinedload(User.addresses))
... .filter(User.name == "spongebob")
... .filter(Address.email_address == "someaddress@foo.com")
... )
>>> result = session.scalars(stmt).unique().all()
SELECT
addresses_1.id AS addresses_1_id,
addresses_1.email_address AS addresses_1_email_address,
addresses_1.user_id AS addresses_1_user_id,
users.id AS users_id, users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users JOIN addresses
ON users.id = addresses.user_id
LEFT OUTER JOIN addresses AS addresses_1
ON users.id = addresses_1.user_id
WHERE users.name = ? AND addresses.email_address = ?
['spongebob', 'someaddress@foo.com']
在上面,我们可以看到这两个 JOIN 具有非常不同的作用。其中一个将完全匹配一行,即 User
和 Address
的 join,其中 Address.email_address=='someaddress@foo.com'
。另一个 LEFT OUTER JOIN 将匹配与 User
相关联的所有 Address
行,并且仅用于填充 User.addresses
集合,对于返回的那些 User
对象。
通过将 joinedload()
的用法更改为另一种加载样式,我们可以完全独立于用于检索我们想要的实际 User
行的 SQL 来更改集合的加载方式。下面我们将 joinedload()
更改为 selectinload()
>>> stmt = (
... select(User)
... .join(User.addresses)
... .options(selectinload(User.addresses))
... .filter(User.name == "spongebob")
... .filter(Address.email_address == "someaddress@foo.com")
... )
>>> result = session.scalars(stmt).all()
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
JOIN addresses ON users.id = addresses.user_id
WHERE
users.name = ?
AND addresses.email_address = ?
['spongebob', 'someaddress@foo.com']
# ... selectinload() emits a SELECT in order
# to load all address records ...
当使用连接迫切加载时,如果查询包含影响 join 外部返回行的修饰符,例如使用 DISTINCT、LIMIT、OFFSET 或等效项时,完成的语句首先被包装在子查询中,并且专门用于连接迫切加载的 join 将应用于子查询。SQLAlchemy 的连接迫切加载会付出额外的努力,甚至更多,以绝对确保它不会影响查询的最终结果,只会影响集合和相关对象的加载方式,无论查询的格式如何。
另请参阅
Select IN 加载¶
在大多数情况下,selectin 加载是迫切加载对象集合的最简单和最有效的方式。selectin 迫切加载不可行的唯一情况是模型使用复合主键,并且后端数据库不支持带 IN 的元组,目前包括 SQL Server。
“Select IN” 迫切加载通过 "selectin"
参数提供给 relationship.lazy
或使用 selectinload()
加载器选项。这种加载样式会发出一个 SELECT,该 SELECT 引用父对象的主键值,或者在多对一关系的情况下,引用子对象的主键值,在 IN 子句内部,以便加载相关关联
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import selectinload
>>> stmt = (
... select(User)
... .options(selectinload(User.addresses))
... .filter(or_(User.name == "spongebob", User.name == "ed"))
... )
>>> result = session.scalars(stmt).all()
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
WHERE users.name = ? OR users.name = ?
('spongebob', 'ed')
SELECT
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses
WHERE addresses.user_id IN (?, ?)
(5, 7)
在上面,第二个 SELECT 引用 addresses.user_id IN (5, 7)
,其中 “5” 和 “7” 是先前加载的两个 User
对象的主键值;在一批对象完全加载后,它们的主键值被注入到第二个 SELECT 的 IN
子句中。由于 User
和 Address
之间的关系具有简单的主 join 条件,并提供可以从 Address.user_id
派生 User
的主键值,因此该语句根本没有 join 或子查询。
对于简单的多对一加载,也不需要 JOIN,因为使用了父对象的外键值
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import selectinload
>>> stmt = select(Address).options(selectinload(Address.user))
>>> result = session.scalars(stmt).all()
SELECT
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id
FROM addresses
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
WHERE users.id IN (?, ?)
(1, 2)
提示
“简单” 的意思是 relationship.primaryjoin
条件表达了 “一” 方的主键和 “多” 方的直接外键之间的相等比较,而没有任何其他条件。
Select IN 加载还支持多对多关系,在多对多关系中,它当前将跨所有三个表进行 JOIN,以匹配一侧到另一侧的行。
关于这种加载方式,需要了解以下几点
该策略一次最多为 500 个父主键值发出一个 SELECT,因为主键被渲染到 SQL 语句中的大型 IN 表达式中。某些数据库(如 Oracle Database)对 IN 表达式的大小有硬性限制,并且 SQL 字符串的总大小不应任意大。
由于 “selectin” 加载依赖于 IN,对于具有复合主键的映射,它必须使用 IN 的 “元组” 形式,其外观类似于
WHERE (table.column_a, table.column_b) IN ((?, ?), (?, ?), (?, ?))
。SQL Server 目前不支持此语法,而 SQLite 至少需要 3.15 版本。SQLAlchemy 中没有特殊的逻辑来提前检查哪些平台支持此语法或不支持此语法;如果针对不支持的平台运行,数据库将立即返回错误。SQLAlchemy 只是运行 SQL 以使其失败的一个优点是,如果特定数据库开始支持此语法,它将无需对 SQLAlchemy 进行任何更改即可工作(SQLite 就是这种情况)。
子查询迫切加载¶
遗留功能
subqueryload()
迫切加载器在很大程度上是遗留功能,它已被 selectinload()
策略所取代,后者设计更简单,对于 Yield Per 等功能更灵活,并且在大多数情况下发出更高效的 SQL 语句。由于 subqueryload()
依赖于重新解释原始 SELECT 语句,因此当给定非常复杂的源查询时,它可能无法有效工作。
对于在 Microsoft SQL Server 后端上使用复合主键的对象的迫切加载集合的特定情况,subqueryload()
可能仍然有用,因为 Microsoft SQL Server 后端继续不支持 “元组 IN” 语法。
子查询加载在操作上类似于 selectin 迫切加载,但是发出的 SELECT 语句是从原始语句派生的,并且具有比 selectin 迫切加载更复杂的查询结构。
子查询迫切加载通过 "subquery"
参数提供给 relationship.lazy
或使用 subqueryload()
加载器选项。
子查询迫切加载的操作是为要加载的每个关系发出第二个 SELECT 语句,一次针对所有结果对象。此 SELECT 语句引用原始 SELECT 语句,包装在子查询内部,以便我们检索返回的主对象相同的主键列表,然后将其链接到要一次加载的所有集合成员的总和
>>> from sqlalchemy import select
>>> from sqlalchemy.orm import subqueryload
>>> stmt = select(User).options(subqueryload(User.addresses)).filter_by(name="spongebob")
>>> results = session.scalars(stmt).all()
SELECT
users.id AS users_id,
users.name AS users_name,
users.fullname AS users_fullname,
users.nickname AS users_nickname
FROM users
WHERE users.name = ?
('spongebob',)
SELECT
addresses.id AS addresses_id,
addresses.email_address AS addresses_email_address,
addresses.user_id AS addresses_user_id,
anon_1.users_id AS anon_1_users_id
FROM (
SELECT users.id AS users_id
FROM users
WHERE users.name = ?) AS anon_1
JOIN addresses ON anon_1.users_id = addresses.user_id
ORDER BY anon_1.users_id, addresses.id
('spongebob',)
关于这种加载方式,需要了解以下几点
与 “selectin” 不同,“subquery” 加载器策略发出的 SELECT 语句需要一个子查询,并将继承原始查询中存在的任何性能限制。子查询本身也可能因所用数据库的特性而产生性能损失。
“subquery” 加载施加了一些特殊的排序要求,以便正常工作。使用
subqueryload()
与限制修饰符(如Select.limit()
或Select.offset()
)结合使用的查询应始终包含针对唯一列(如主键)的Select.order_by()
,以便subqueryload()
发出的附加查询包含与父查询使用的排序相同的排序。如果没有它,内部查询可能会返回错误的行# incorrect, no ORDER BY stmt = select(User).options(subqueryload(User.addresses).limit(1)) # incorrect if User.name is not unique stmt = select(User).options(subqueryload(User.addresses)).order_by(User.name).limit(1) # correct stmt = ( select(User) .options(subqueryload(User.addresses)) .order_by(User.name, User.id) .limit(1) )
当在多层深度迫切加载中使用 “subquery” 加载时,也会产生额外的性能/复杂性问题,因为子查询将重复嵌套。
“subquery” 加载与 Yield Per 提供的 “批量” 加载不兼容,无论是对于集合关系还是标量关系。
由于上述原因,应优先选择 “selectin” 策略而不是 “subquery”。
另请参阅
使用哪种加载方式?¶
使用哪种类型的加载通常取决于优化 SQL 执行次数、发出的 SQL 复杂性和获取的数据量之间的权衡。
一对多/多对多集合 - selectinload()
通常是最佳的加载策略。它发出一个额外的 SELECT,该 SELECT 使用尽可能少的表,使原始语句不受影响,并且对于任何类型的原始查询都最灵活。它唯一的主要限制是在后端上使用带有复合主键的表,该后端不支持 “元组 IN”,目前包括 SQL Server 和非常旧的 SQLite 版本;所有其他包含的后端都支持它。
多对一 - joinedload()
策略是最通用的策略。在特殊情况下,如果潜在的相关值数量非常少,immediateload()
策略也可能有用,因为如果相关对象已经存在,则此策略将从本地 Session
中获取对象,而不会发出任何 SQL。
多态迫切加载¶
支持在每个迫切加载的基础上指定多态选项。有关 PropComparator.of_type()
方法与 with_polymorphic()
函数结合使用的示例,请参阅 多态子类型的迫切加载 部分。
通配符加载策略¶
joinedload()
、subqueryload()
、lazyload()
、selectinload()
和 raiseload()
都可以用于为特定查询设置 relationship()
加载的默认样式,影响语句中未另行指定的所有 relationship()
映射属性。此功能通过传递字符串 '*'
作为任何这些选项的参数来提供
from sqlalchemy import select
from sqlalchemy.orm import lazyload
stmt = select(MyClass).options(lazyload("*"))
在上面,lazyload('*')
选项将取代该查询中使用的所有 relationship()
构造的 lazy
设置,但使用 lazy='write_only'
或 lazy='dynamic'
的构造除外。
如果某些关系指定了 lazy='joined'
或 lazy='selectin'
,例如,使用 lazyload('*')
将单方面导致所有这些关系使用 'select'
加载,例如,在访问每个属性时发出 SELECT 语句。
该选项不会取代查询中声明的加载器选项,例如 joinedload()
、selectinload()
等。下面的查询仍将对 widget
关系使用连接加载
from sqlalchemy import select
from sqlalchemy.orm import lazyload
from sqlalchemy.orm import joinedload
stmt = select(MyClass).options(lazyload("*"), joinedload(MyClass.widget))
虽然上面 joinedload()
的指令将生效,无论它出现在 lazyload()
选项之前还是之后,但如果传递了多个都包含 "*"
的选项,则最后一个选项将生效。
每实体通配符加载策略¶
通配符加载器策略的一个变体是能够在每实体基础上设置策略。例如,如果查询 User
和 Address
,我们可以指示 Address
上的所有关系都使用延迟加载,同时保持 User
的加载器策略不受影响,方法是首先应用 Load
对象,然后将 *
指定为链式选项
from sqlalchemy import select
from sqlalchemy.orm import Load
stmt = select(User, Address).options(Load(Address).lazyload("*"))
在上面,Address
上的所有关系都将设置为延迟加载。
将显式 Join/语句路由到迫切加载的集合中¶
joinedload()
的行为是自动创建 join,使用匿名别名作为目标,其结果被路由到已加载对象上的集合和标量引用中。通常情况下,查询已经包含表示特定集合或标量引用所需的 join,并且由 joinedload 功能添加的 join 是冗余的 - 但您仍然希望填充集合/引用。
为此,SQLAlchemy 提供了 contains_eager()
选项。此选项的使用方式与 joinedload()
选项相同,不同之处在于它假定 Select
对象将显式包含适当的 join,通常使用诸如 Select.join()
等方法。在下面,我们指定 User
和 Address
之间的 join,并额外将其建立为 User.addresses
迫切加载的基础
from sqlalchemy.orm import contains_eager
stmt = select(User).join(User.addresses).options(contains_eager(User.addresses))
如果语句的 “迫切” 部分是 “别名”,则应使用 PropComparator.of_type()
指定路径,这允许传递特定的 aliased()
构造
# use an alias of the Address entity
adalias = aliased(Address)
# construct a statement which expects the "addresses" results
stmt = (
select(User)
.outerjoin(User.addresses.of_type(adalias))
.options(contains_eager(User.addresses.of_type(adalias)))
)
# get results normally
r = session.scalars(stmt).unique().all()
SELECT
users.user_id AS users_user_id,
users.user_name AS users_user_name,
adalias.address_id AS adalias_address_id,
adalias.user_id AS adalias_user_id,
adalias.email_address AS adalias_email_address,
(...other columns...)
FROM users
LEFT OUTER JOIN email_addresses AS email_addresses_1
ON users.user_id = email_addresses_1.user_id
作为 contains_eager()
参数给出的路径需要是从起始实体的完整路径。例如,如果我们正在加载 Users->orders->Order->items->Item
,则该选项将用作
stmt = select(User).options(contains_eager(User.orders).contains_eager(Order.items))
使用 contains_eager() 加载自定义过滤的集合结果¶
当我们使用 contains_eager()
时,我们 正在构建我们自己的 SQL,该 SQL 将用于填充集合。由此自然而然地,我们可以选择修改集合旨在存储的值,通过编写我们的 SQL 来加载集合或标量属性的元素子集。
提示
SQLAlchemy 现在有一种更简单的方法来做到这一点,它允许将 WHERE 条件直接添加到加载器选项,例如 joinedload()
和 selectinload()
,使用 PropComparator.and_()
。请参阅 向加载器选项添加条件 部分以获取示例。
如果相关集合要使用比简单 WHERE 子句更复杂的 SQL 条件或修饰符进行查询,则此处描述的技术仍然适用。
例如,我们可以加载一个 User
对象,并通过过滤连接的数据,使用 contains_eager()
路由它,从而仅将特定的地址急切加载到其 .addresses
集合中,同时使用 Populate Existing 以确保任何已加载的集合都被覆盖
stmt = (
select(User)
.join(User.addresses)
.filter(Address.email_address.like("%@aol.com"))
.options(contains_eager(User.addresses))
.execution_options(populate_existing=True)
)
上述查询将仅加载包含至少一个 Address
对象的 User
对象,该 Address
对象在其 email
字段中包含子字符串 'aol.com'
;User.addresses
集合将仅包含这些 Address
条目,而不包含实际上与该集合关联的任何其他 Address
条目。
提示
在所有情况下,除非告知这样做,否则 SQLAlchemy ORM 不会覆盖已加载的属性和集合。由于正在使用 标识映射,因此通常 ORM 查询返回的对象实际上已经存在并加载在内存中。因此,当使用 contains_eager()
以替代方式填充集合时,通常最好使用如上所示的 Populate Existing,以便使用新数据刷新已加载的集合。populate_existing
选项将重置所有已存在的属性,包括待处理的更改,因此请确保在使用它之前刷新所有数据。将 Session
与其 autoflush 的默认行为一起使用就足够了。
注意
我们使用 contains_eager()
加载的自定义集合不是“粘性的”;也就是说,下次加载此集合时,它将使用其通常的默认内容加载。如果对象已过期,则集合可能会被重新加载,这发生在假设默认会话设置的情况下使用 Session.commit()
、Session.rollback()
方法时,或者使用 Session.expire_all()
或 Session.expire()
方法时。
另请参阅
向加载器选项添加条件 - 现代 API 允许在任何关系加载器选项中直接使用 WHERE 条件
关系加载器 API¶
对象名称 | 描述 |
---|---|
contains_eager(*keys, **kw) |
指示应从查询中手动声明的列中急切加载给定的属性。 |
defaultload(*keys) |
指示属性应使用其预定义的加载器样式加载。 |
immediateload(*keys, [recursion_depth]) |
指示应使用即时加载和每个属性的 SELECT 语句加载给定的属性。 |
joinedload(*keys, **kw) |
指示应使用连接的急切加载来加载给定的属性。 |
lazyload(*keys) |
指示应使用“延迟”加载来加载给定的属性。 |
表示加载器选项,这些选项修改启用 ORM 的 |
|
noload(*keys) |
指示给定的关系属性应保持未加载状态。 |
raiseload(*keys, **kw) |
指示如果访问给定的属性,应引发错误。 |
selectinload(*keys, [recursion_depth]) |
指示应使用 SELECT IN 急切加载来加载给定的属性。 |
subqueryload(*keys) |
指示应使用子查询急切加载来加载给定的属性。 |
- function sqlalchemy.orm.contains_eager(*keys: Literal['*'] | QueryableAttribute[Any], **kw: Any) → _AbstractLoad¶
指示应从查询中手动声明的列中急切加载给定的属性。
此函数是
Load
接口的一部分,并支持方法链式和独立操作。该选项与显式 join 结合使用,该 join 加载所需的行,即:
sess.query(Order).join(Order.user).options(contains_eager(Order.user))
上述查询将从
Order
实体连接到其相关的User
实体,并且返回的Order
对象将预先填充Order.user
属性。它也可以用于自定义急切加载集合中的条目;查询通常会希望使用 Populate Existing 执行选项,假设父对象的主集合可能已被加载
sess.query(User).join(User.addresses).filter( Address.email_address.like("%@aol.com") ).options(contains_eager(User.addresses)).populate_existing()
有关完整的用法详细信息,请参阅 将显式 Join/语句路由到急切加载的集合中 部分。
- function sqlalchemy.orm.defaultload(*keys: Literal['*'] | QueryableAttribute[Any]) → _AbstractLoad¶
指示属性应使用其预定义的加载器样式加载。
此加载选项的行为是不要更改属性的当前加载样式,这意味着将使用先前配置的样式,或者,如果未选择先前的样式,则将使用默认加载。
此方法用于链接到属性链中更深层次的其他加载器选项,而不会更改链中链接的加载器样式。例如,为元素的元素设置连接的急切加载
session.query(MyClass).options( defaultload(MyClass.someattribute).joinedload( MyOtherClass.someotherattribute ) )
defaultload()
也可用于在相关类上设置列级选项,即defer()
和undefer()
session.scalars( select(MyClass).options( defaultload(MyClass.someattribute) .defer("some_column") .undefer("some_other_column") ) )
- function sqlalchemy.orm.immediateload(*keys: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → _AbstractLoad¶
指示应使用即时加载和每个属性的 SELECT 语句加载给定的属性。
加载是通过“lazyloader”策略实现的,并且不会触发任何额外的急切加载器。
immediateload()
选项通常被selectinload()
选项取代,后者通过为所有加载的对象发出 SELECT 来更有效地执行相同的任务。此函数是
Load
接口的一部分,并支持方法链式和独立操作。- 参数:
recursion_depth¶ –
可选的 int;当与自引用关系结合设置为正整数时,指示“selectin”加载将自动继续深入多个级别,直到找不到任何项目为止。
注意
immediateload.recursion_depth
选项当前仅支持自引用关系。目前还没有自动遍历涉及多个关系的递归结构的选项。警告
此参数是新的且是实验性的,应视为“alpha”状态
2.0 版本新增: 添加了
immediateload.recursion_depth
- function sqlalchemy.orm.joinedload(*keys: Literal['*'] | QueryableAttribute[Any], **kw: Any) → _AbstractLoad¶
指示应使用连接的急切加载来加载给定的属性。
此函数是
Load
接口的一部分,并支持方法链式和独立操作。示例
# joined-load the "orders" collection on "User" select(User).options(joinedload(User.orders)) # joined-load Order.items and then Item.keywords select(Order).options(joinedload(Order.items).joinedload(Item.keywords)) # lazily load Order.items, but when Items are loaded, # joined-load the keywords collection select(Order).options(lazyload(Order.items).joinedload(Item.keywords))
- 参数:
innerjoin¶ –
如果
True
,则指示连接的急切加载应使用内连接,而不是默认的左外连接select(Order).options(joinedload(Order.user, innerjoin=True))
为了将多个急切连接链接在一起,其中一些可能是 OUTER,另一些可能是 INNER,使用右嵌套连接来链接它们
select(A).options( joinedload(A.bs, innerjoin=False).joinedload(B.cs, innerjoin=True) )
上面的查询,通过“outer”连接链接 A.bs,并通过“inner”连接链接 B.cs,会将连接呈现为“a LEFT OUTER JOIN (b JOIN c)”。当使用旧版本的 SQLite (< 3.7.16) 时,这种形式的 JOIN 会被转换为使用完整的子查询,因为否则这种语法不被直接支持。
innerjoin
标志也可以用术语"unnested"
来表示。这表示应使用 INNER JOIN,除非连接链接到左侧的 LEFT OUTER JOIN,在这种情况下,它将呈现为 LEFT OUTER JOIN。例如,假设A.bs
是一个外连接select(A).options(joinedload(A.bs).joinedload(B.cs, innerjoin="unnested"))
上面的连接将呈现为“a LEFT OUTER JOIN b LEFT OUTER JOIN c”,而不是“a LEFT OUTER JOIN (b JOIN c)”。
注意
“unnested”标志不影响从多对多关联表(例如,配置为
relationship.secondary
的表)到目标表的 JOIN;为了结果的正确性,这些连接始终是 INNER,因此如果链接到 OUTER 连接,则会进行右嵌套。注意
joinedload()
生成的连接是匿名别名。无法修改连接进行的条件,ORM 启用的Select
或旧式Query
也无法以任何方式引用这些连接,包括排序。有关更多详细信息,请参阅 急切连接加载的禅宗。要生成特定的 SQL JOIN(显式可用),请使用
Select.join()
和Query.join()
。要将显式 JOIN 与集合的急切加载结合使用,请使用contains_eager()
;请参阅 将显式 Join/语句路由到急切加载的集合中。
- function sqlalchemy.orm.lazyload(*keys: Literal['*'] | QueryableAttribute[Any]) → _AbstractLoad¶
指示应使用“延迟”加载来加载给定的属性。
此函数是
Load
接口的一部分,并支持方法链式和独立操作。
- class sqlalchemy.orm.Load¶
表示加载器选项,这些选项修改启用 ORM 的
Select
或旧式Query
的状态,以便影响各种映射属性的加载方式。在大多数情况下,当使用查询选项(如
joinedload()
、defer()
或类似选项)时,Load
对象在幕后隐式使用。通常,除非在某些非常特定的情况下,否则不会直接实例化它。另请参阅
每个实体的通配符加载策略 - 说明了直接使用
Load
可能有用的示例成员
contains_eager(), defaultload(), defer(), get_children(), immediateload(), inherit_cache, joinedload(), lazyload(), load_only(), noload(), options(), process_compile_state(), process_compile_state_replaced_entities(), propagate_to_loaders, raiseload(), selectin_polymorphic(), selectinload(), subqueryload(), undefer(), undefer_group(), with_expression()
类签名
class
sqlalchemy.orm.Load
(sqlalchemy.orm.strategy_options._AbstractLoad
)-
method
sqlalchemy.orm.Load.
contains_eager(attr: _AttrType, alias: _FromClauseArgument | None = None, _is_chain: bool = False, _propagate_to_loaders: bool = False) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.contains_eager
方法,属于sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用contains_eager()
选项。有关用法示例,请参阅
contains_eager()
。
-
method
sqlalchemy.orm.Load.
defaultload(attr: Literal['*'] | QueryableAttribute[Any]) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.defaultload
方法,属于sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用defaultload()
选项。有关用法示例,请参阅
defaultload()
。
-
method
sqlalchemy.orm.Load.
defer(key: Literal['*'] | QueryableAttribute[Any], raiseload: bool = False) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.defer
方法,属于sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用defer()
选项。有关用法示例,请参阅
defer()
。
-
method
sqlalchemy.orm.Load.
get_children(*, omit_attrs: Tuple[str, ...] = (), **kw: Any) → Iterable[HasTraverseInternals]¶ 继承自
HasTraverseInternals.get_children()
方法,属于HasTraverseInternals
返回此
HasTraverseInternals
的直接子HasTraverseInternals
元素。这用于访问遍历。
**kw 可能包含更改返回集合的标志,例如,为了减少更大的遍历,返回项目子集,或者从不同的上下文(例如,模式级集合而不是子句级集合)返回子项。
-
method
sqlalchemy.orm.Load.
immediateload(attr: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.immediateload
方法,属于sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用immediateload()
选项。请参阅
immediateload()
以获取使用示例。
-
attribute
sqlalchemy.orm.Load.
inherit_cache: bool | None = None¶ 继承自
HasCacheKey.inherit_cache
属性,来自HasCacheKey
指示此
HasCacheKey
实例是否应使用其直接父类使用的缓存键生成方案。该属性默认为
None
,表示构造尚未考虑是否适合参与缓存;这在功能上等同于将值设置为False
,但还会发出警告。如果与对象对应的 SQL 不会根据此类的局部属性(而不是其父类)而更改,则可以将此标志设置为
True
在特定类上。另请参阅
为自定义构造启用缓存支持 - 有关为第三方或用户定义的 SQL 构造设置
HasCacheKey.inherit_cache
属性的一般指南。
-
method
sqlalchemy.orm.Load.
joinedload(attr: Literal['*'] | QueryableAttribute[Any], innerjoin: bool | None = None) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.joinedload
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用joinedload()
选项。请参阅
joinedload()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
lazyload(attr: Literal['*'] | QueryableAttribute[Any]) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.lazyload
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用lazyload()
选项。请参阅
lazyload()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
load_only(*attrs: Literal['*'] | QueryableAttribute[Any], raiseload: bool = False) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.load_only
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用load_only()
选项。请参阅
load_only()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
noload(attr: Literal['*'] | QueryableAttribute[Any]) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.noload
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用noload()
选项。请参阅
noload()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
options(*opts: _AbstractLoad) → Self¶ 将一系列选项作为子选项应用于此
Load
对象。例如:
query = session.query(Author) query = query.options( joinedload(Author.book).options( load_only(Book.summary, Book.excerpt), joinedload(Book.citations).options(joinedload(Citation.author)), ) )
1.3.6 版本新增。
-
method
sqlalchemy.orm.Load.
process_compile_state(compile_state: ORMCompileState) → None¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.process_compile_state
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
对给定的
ORMCompileState
应用修改。此方法是特定
CompileStateOption
实现的一部分,仅在编译 ORM 查询时在内部调用。
-
method
sqlalchemy.orm.Load.
process_compile_state_replaced_entities(compile_state: ORMCompileState, mapper_entities: Sequence[_MapperEntity]) → None¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.process_compile_state_replaced_entities
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
对给定的
ORMCompileState
应用修改,给定被 with_only_columns() 或 with_entities() 替换的实体。此方法是特定
CompileStateOption
实现的一部分,仅在编译 ORM 查询时在内部调用。1.4.19 版本新增。
-
attribute
sqlalchemy.orm.Load.
propagate_to_loaders: bool¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.propagate_to_loaders
属性,来自sqlalchemy.orm.strategy_options._AbstractLoad
如果为 True,则指示此选项应沿用到“辅助”SELECT 语句,这些语句用于关系延迟加载器以及属性加载/刷新操作。
-
method
sqlalchemy.orm.Load.
raiseload(attr: Literal['*'] | QueryableAttribute[Any], sql_only: bool = False) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.raiseload
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用raiseload()
选项。请参阅
raiseload()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
selectin_polymorphic(classes: Iterable[Type[Any]]) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.selectin_polymorphic
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用selectin_polymorphic()
选项。请参阅
selectin_polymorphic()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
selectinload(attr: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.selectinload
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用selectinload()
选项。请参阅
selectinload()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
subqueryload(attr: Literal['*'] | QueryableAttribute[Any]) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.subqueryload
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用subqueryload()
选项。请参阅
subqueryload()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
undefer(key: Literal['*'] | QueryableAttribute[Any]) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.undefer
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用undefer()
选项。请参阅
undefer()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
undefer_group(name: str) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.undefer_group
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用undefer_group()
选项。请参阅
undefer_group()
以获取使用示例。
-
method
sqlalchemy.orm.Load.
with_expression(key: _AttrType, expression: _ColumnExpressionArgument[Any]) → Self¶ 继承自
sqlalchemy.orm.strategy_options._AbstractLoad.with_expression
方法,来自sqlalchemy.orm.strategy_options._AbstractLoad
生成一个新的
Load
对象,并应用with_expression()
选项。请参阅
with_expression()
以获取使用示例。
-
method
- function sqlalchemy.orm.noload(*keys: Literal['*'] | QueryableAttribute[Any]) → _AbstractLoad¶
指示给定的关系属性应保持未加载状态。
关系属性在访问时将返回
None
,而不会产生任何加载效果。此函数是
Load
接口的一部分,并支持方法链式和独立操作。noload()
仅适用于relationship()
属性。遗留功能
noload()
选项是遗留的。因为它强制集合为空,这总是导致非直观且难以预测的结果。在现代 SQLAlchemy 中,此选项没有合理的用途。另请参阅
- function sqlalchemy.orm.raiseload(*keys: Literal['*'] | QueryableAttribute[Any], **kw: Any) → _AbstractLoad¶
指示如果访问给定的属性,应引发错误。
配置了
raiseload()
的关系属性在访问时会引发InvalidRequestError
。 这种方法的典型用途是当应用程序尝试确保在特定上下文中访问的所有关系属性都已通过预先加载加载。 此策略将导致它们立即引发错误,而无需通读 SQL 日志以确保未发生延迟加载。raiseload()
仅适用于relationship()
属性。 为了将 raise-on-SQL 行为应用于基于列的属性,请使用defer.raiseload
参数在defer()
加载器选项上。- 参数:
sql_only¶ – 如果为 True,则仅当延迟加载将发出 SQL 时引发,而不是仅当它正在检查标识映射或确定相关值应仅为 None(由于缺少键)时才引发。 当为 False 时,此策略将针对所有类型的关系加载引发。
此函数是
Load
接口的一部分,并支持方法链式和独立操作。
- 函数 sqlalchemy.orm.selectinload(*keys: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → _AbstractLoad¶
指示应使用 SELECT IN 急切加载来加载给定的属性。
此函数是
Load
接口的一部分,并支持方法链式和独立操作。示例
# selectin-load the "orders" collection on "User" select(User).options(selectinload(User.orders)) # selectin-load Order.items and then Item.keywords select(Order).options( selectinload(Order.items).selectinload(Item.keywords) ) # lazily load Order.items, but when Items are loaded, # selectin-load the keywords collection select(Order).options(lazyload(Order.items).selectinload(Item.keywords))
- 参数:
recursion_depth¶ –
可选的 int;当与自引用关系结合设置为正整数时,指示“selectin”加载将自动继续深入多个级别,直到找不到任何项目为止。
注意
selectinload.recursion_depth
选项目前仅支持自引用关系。目前还没有选项可以自动遍历涉及多个关系的递归结构。此外,
selectinload.recursion_depth
参数是新的实验性功能,在 2.0 系列中应被视为 “alpha” 状态。2.0 版本新增: 添加了
selectinload.recursion_depth
- 函数 sqlalchemy.orm.subqueryload(*keys: Literal['*'] | QueryableAttribute[Any]) → _AbstractLoad¶
指示应使用子查询急切加载来加载给定的属性。
此函数是
Load
接口的一部分,并支持方法链式和独立操作。示例
# subquery-load the "orders" collection on "User" select(User).options(subqueryload(User.orders)) # subquery-load Order.items and then Item.keywords select(Order).options( subqueryload(Order.items).subqueryload(Item.keywords) ) # lazily load Order.items, but when Items are loaded, # subquery-load the keywords collection select(Order).options(lazyload(Order.items).subqueryload(Item.keywords))
flambé! 龙和 The Alchemist 图像设计由 Rotem Yaari 创作并慷慨捐赠。
使用 Sphinx 7.2.6 创建。文档最后生成时间:周二 2025年3月11日 下午 02:40:17 EDT