SqlAlchemy 2.0 中文文档(十九)(3)

简介: SqlAlchemy 2.0 中文文档(十九)

SqlAlchemy 2.0 中文文档(十九)(2)https://developer.aliyun.com/article/1562931


关系加载器 API

对象名称 描述
contains_eager(*keys, **kw) 指示给定属性应通过手动在查询中声明的列进行急加载。
defaultload(*keys) 指示属性应使用其预定义的加载器样式加载。
immediateload(*keys, [recursion_depth]) 指示给定属性应使用立即加载,并使用每个属性的 SELECT 语句。
joinedload(*keys, **kw) 指示给定属性应使用连接的急加载。
lazyload(*keys) 指示给定属性应使用“懒”加载。
Load 表示加载器选项,可修改 ORM 启用的Select或传统Query的状态,以影响如何加载各种映射属性。
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接口的一部分,支持方法链和独立操作。

此选项与加载所需行的显式连接一起使用,即:

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

有关完整使用详细信息,请参阅将显式连接/语句路由到急加载集合部分。

另请参见

关系加载技术

将显式连接/语句路由到急加载集合

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

另请参见

使用 Load.options()指定子选项

Load.options()

function sqlalchemy.orm.immediateload(*keys: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → _AbstractLoad

表示给定属性应使用具有每个属性 SELECT 语句的立即加载进行加载。

加载是使用“lazyloader”策略实现的,并且不会触发任何其他急加载器。

immediateload() 选项一般被selectinload() 选项取代,后者通过为所有加载的对象发出一个 SELECT 更有效地执行相同的任务。

此函数是Load接口的一部分,支持方法链接和独立操作。

参数:

递归深度

可选的整数;当与自引用关系一起设置为正整数时,表示“选择加载”将自动继续到没有找到项目为止的那么多级别深度。

注意

immediateload.recursion_depth 选项当前仅支持自引用关系。目前还没有选项可以自动遍历具有多个涉及的关系的递归结构。

警告

此参数是新的实验性参数,应视为“alpha”状态

新版 2.0 中新增 immediateload.recursion_depth

另请参阅

关联加载技术

选择 IN 加载

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 是一个 outerjoin:

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;为了结果的正确性,这些 JOIN 始终是 INNER JOIN,因此如果与 OUTER JOIN 相关联,则为右嵌套。

注意

joinedload()生成的 JOIN 是匿名别名的。 JOIN 进行的标准无法修改,也无法通过 ORM 启用的Select或传统的Query以任何方式引用这些 JOIN,包括排序。有关详细信息,请参阅关联及时加载的禅意。

要生成明确可用的特定 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()

类签名

sqlalchemy.orm.Load (sqlalchemy.orm.strategy_options._AbstractLoad)

method contains_eager(attr: _AttrType, alias: _FromClauseArgument | None = None, _is_chain: bool = False) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.contains_eager 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

生成一个应用了contains_eager()选项的新Load对象。

有关用法示例,请参见contains_eager()

method defaultload(attr: Literal['*'] | QueryableAttribute[Any]) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.defaultload 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

生成一个应用了defaultload()选项的新Load对象。

有关用法示例,请参见defaultload()

method defer(key: Literal['*'] | QueryableAttribute[Any], raiseload: bool = False) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.defer 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

生成一个应用了defer()选项的新Load对象。

有关用法示例,请参见defer()

method get_children(*, omit_attrs: Tuple[str, ...] = (), **kw: Any) → Iterable[HasTraverseInternals]

继承自 HasTraverseInternals.get_children() 方法的 HasTraverseInternals

返回此HasTraverseInternals的直接子HasTraverseInternals元素。

用于访问遍历。

**kw 可能包含更改返回集合的标志,例如返回子集以减少更大的遍历,或者返回来自不同上下文的子项(例如模式级集合而不是子句级集合)。

method immediateload(attr: Literal['*'] | QueryableAttribute[Any], recursion_depth: int | None = None) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.immediateload 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

使用immediateload()选项应用于生成新的Load对象。

查看immediateload()以获取用法示例。

attribute inherit_cache: bool | None = None

继承自 HasCacheKeyHasCacheKey.inherit_cache 属性

指示此HasCacheKey实例是否应使用其直接超类使用的缓存键生成方案。

该属性默认为None,表示构造尚未考虑是否适合参与缓存;这在功能上等同于将值设置为False,只是还会发出警告。

如果与对象对应的 SQL 不基于本类的本地属性而是基于其超类,则可以在特定类上将此标志设置为True

另请参阅

为自定义构造启用缓存支持 - 为第三方或用户定义的 SQL 构造设置HasCacheKey.inherit_cache属性的一般指南。

method joinedload(attr: Literal['*'] | QueryableAttribute[Any], innerjoin: bool | None = None) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.joinedload 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

使用joinedload()选项应用于生成新的Load对象。

查看joinedload()以获取用法示例。

method lazyload(attr: Literal['*'] | QueryableAttribute[Any]) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.lazyload 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

使用lazyload()选项应用于生成新的Load对象。

查看lazyload()以获取用法示例。

method load_only(*attrs: Literal['*'] | QueryableAttribute[Any], raiseload: bool = False) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.load_only 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

使用已应用了 load_only() 选项的新 Load 对象。

有关使用示例,请参见 load_only()

method noload(attr: Literal['*'] | QueryableAttribute[Any]) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.noload 方法 sqlalchemy.orm.strategy_options._AbstractLoad

使用已应用了 noload() 选项的新 Load 对象。

有关使用示例,请参见 noload()

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

参数:

*opts – 应用于此 Load 对象指定路径的一系列加载器选项对象(最终为 Load 对象)。

自版本 1.3.6 新增。

另请参阅

defaultload()

使用 Load.options() 指定子选项

method process_compile_state(compile_state: ORMCompileState) → None

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.process_compile_state 方法 sqlalchemy.orm.strategy_options._AbstractLoad

对给定的 ORMCompileState 应用修改。

此方法是特定 CompileStateOption 实现的一部分,并且仅在编译 ORM 查询时内部调用。

method 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 propagate_to_loaders: bool

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.propagate_to_loaders 的属性 sqlalchemy.orm.strategy_options._AbstractLoad

如果为 True,则指示此选项应该随着“次要”SELECT 语句一起传递,这些语句会出现在关系惰性加载器以及属性加载/刷新操作中。

method raiseload(attr: Literal['*'] | QueryableAttribute[Any], sql_only: bool = False) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.raiseload 方法 sqlalchemy.orm.strategy_options._AbstractLoad

使用已应用了 raiseload() 选项的新 Load 对象。

有关使用示例,请参见 raiseload()

method 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 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 subqueryload(attr: Literal['*'] | QueryableAttribute[Any]) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.subqueryload 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

使用 Load 对象,并应用 subqueryload() 选项。

查看 subqueryload() 以获取使用示例。

method undefer(key: Literal['*'] | QueryableAttribute[Any]) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.undefer 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

使用 Load 对象,并应用 undefer() 选项。

查看 undefer() 以获取使用示例。

method undefer_group(name: str) → Self

继承自 sqlalchemy.orm.strategy_options._AbstractLoad.undefer_group 方法的 sqlalchemy.orm.strategy_options._AbstractLoad

使用 Load 对象,并应用 undefer_group() 选项。

查看 undefer_group() 以获取使用示例。

method 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() 以获取使用示例。

function sqlalchemy.orm.noload(*keys: Literal['*'] | QueryableAttribute[Any]) → _AbstractLoad

指示给定的关系属性应保持未加载状态。

当访问关系属性而不产生任何加载效果时,关系属性将返回 None

此函数是 Load 接口的一部分,并支持方法链式和独立操作。

noload() 仅适用于 relationship() 属性。

注意

将此加载策略设置为使用 relationship.lazy 参数的默认策略可能会导致刷新时出现问题,比如删除操作需要加载相关对象,而返回的却是 None

另请参阅

关系加载技术

function sqlalchemy.orm.raiseload(*keys: Literal['*'] | QueryableAttribute[Any], **kw: Any) → _AbstractLoad

表示如果访问将引发错误的给定属性。

使用 raiseload() 配置的关系属性在访问时会引发 InvalidRequestError。此方法通常有用的方式是,当应用程序试图确保在特定上下文中访问的所有关系属性都已通过激进加载加载时。而不是必须阅读 SQL 日志以确保不发生懒加载,此策略将立即导致它们引发。

raiseload() 仅适用于 relationship() 属性。要将 raise-on-SQL 行为应用于基于列的属性,请在 defer() 加载选项的 defer.raiseload 参数上使用。

参数:

sql_only – 如果为 True,则仅在懒加载将发出 SQL 时引发,但如果仅检查标识映射或确定由于缺少键而相关值应为 None,则不会引发。当为 False 时,该策略将引发所有类型的关系加载。

此函数是 Load 接口的一部分,并支持方法链和独立操作。

另请参阅

关系加载技术

使用 raiseload 避免不必要的懒加载

使用 raiseload 避免延迟列加载

function 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

可选整数;与自引用关系结合设置为正整数时,指示“选择加载”将自动继续加载到没有找到项目为止的那么多级。

注意

selectinload.recursion_depth 选项目前仅支持自引用关系。目前还没有自动遍历涉及多个关系的递归结构的选项。

此外,selectinload.recursion_depth 参数是新的实验性参数,应该在 2.0 系列中视为“alpha”状态。

2.0 版本新增:添加了selectinload.recursion_depth

另请参阅

关系加载技术

选择 IN 加载

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

另请参阅

关系加载技术

子查询急加载

关系加载样式总结

关系加载的主要形式包括:

  • 延迟加载 - 通过lazy='select'lazyload() 选项可用,这是在属性访问时发出 SELECT 语句以延迟加载单个对象上的相关引用的加载形式。延迟加载是所有未指示relationship.lazy 选项的所有relationship() 构造的默认加载样式。延迟加载详细信息请参阅延迟加载。
  • 选择 IN 加载 - 通过lazy='selectin'selectinload() 选项可用,此加载形式发出第二个(或更多)SELECT 语句,将父对象的主键标识符组装成一个 IN 子句,以便通过主键一次加载所有相关集合/标量引用的成员。选择 IN 加载详细信息请参阅选择 IN 加载。
  • 连接加载 - 通过lazy='joined'joinedload() 选项可用,此加载形式将 JOIN 应用于给定的 SELECT 语句,以便相关行在同一结果集中加载。连接急加载详细信息请参阅连接急加载。
  • 抛出加载 - 可通过lazy='raise'lazy='raise_on_sql'raiseload()选项使用,这种加载方式在通常发生惰性加载的同时触发,但会引发 ORM 异常,以防止应用程序进行不必要的惰性加载。关于抛出加载的介绍请参阅使用 raiseload 防止不必要的惰性加载。
  • 子查询加载 - 可通过lazy='subquery'subqueryload()选项使用,这种加载方式会发出第二个 SELECT 语句,该语句重新陈述原始查询嵌入到子查询中,然后将该子查询与相关表进行 JOIN,以一次加载所有相关集合/标量引用的成员。子查询急切加载的详细信息请参阅子查询急切加载。
  • 仅写加载 - 可通过lazy='write_only'使用,或者通过使用Relationship对象的左侧进行注释,并使用WriteOnlyMapped注解。这种仅限集合加载样式会产生一种替代的属性仪器,从不从数据库隐式加载记录,而是仅允许WriteOnlyCollection.add()WriteOnlyCollection.add_all()WriteOnlyCollection.remove()方法。通过调用使用WriteOnlyCollection.select()方法构造的 SELECT 语句来查询集合。关于仅写加载的讨论请参阅仅写关系。
  • 动态加载 - 通过lazy='dynamic'可用,或者通过使用DynamicMapped注释来注释Relationship对象的左侧。这是一种传统的仅集合加载器样式,当访问集合时会生成一个Query对象,允许针对集合内容发出自定义 SQL。然而,动态加载器在各种情况下会隐式迭代底层集合,这使得它们对于管理真正大型集合不太有用。动态加载器被“仅写入”集合取代,这将阻止在任何情况下隐式加载底层集合。动态加载器在动态关系加载器中讨论。

在映射时间配置加载策略

特定关系的加载策略可以在映射时间配置,以在加载映射类型的对象的所有情况下发生,没有任何修改它的查询级选项的情况下。这是使用relationship()relationship.lazy参数进行配置的;该参数的常见值包括selectselectinjoined

下面的示例说明了在一对多关系示例中,配置Parent.children关系以在发出Parent对象的 SELECT 语句时使用 Select IN loading:

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

在使用限制条件时,如果特定集合已加载,则不会刷新;为了确保新条件生效,请应用 Populate Existing 执行选项:

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 对象是从指定了不同选项集的后续查询中访问的,情况仍然如此。要在不清除并重新加载现有对象的情况下更改选项,必须使用 Populate Existing 执行选项显式设置它们:

# 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 版本可能会增加更多操作已加载对象的加载器选项的替代方法。### 向加载器选项添加条件

用于指示加载器选项的关系属性包括在创建的联接的 ON 子句或涉及的 WHERE 条件中添加附加过滤条件的能力,具体取决于加载器策略。这可以通过使用 PropComparator.and_() 方法来实现,该方法将通过选项传递,从而将加载的结果限制为给定的过滤条件:

from sqlalchemy import select
from sqlalchemy.orm import lazyload
stmt = select(A).options(lazyload(A.bs.and_(B.id > 5)))

在使用限制条件时,如果特定集合已经加载,它将不会被刷新;为了确保新的条件生效,应用 Populate Existing 执行选项:

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”语句。

可以使用 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 加一问题,即对于加载的任何 N  个对象,访问它们的延迟加载属性意味着将会发出 N+1 个 SELECT 语句。在 SQLAlchemy 中,解决 N  加一问题的常规方法是利用其非常强大的急切加载系统。然而,急切加载要求提前使用 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("*"))

上述通配符将适用于所有关系,不仅限于除 items 外的 Order,还包括 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() 指令的情况下执行此操作。

另请参阅

通配符加载策略

使用 raiseload 防止延迟列加载 ### 使用 raiseload 防止不需要的延迟加载

lazyload() 策略产生了一个最常见的对象关系映射中提到的问题之一的效果;N  加一问题,它说明对于加载的任何 N 个对象,访问它们的延迟加载属性意味着会有 N+1 个 SELECT 语句被发送。在 SQLAlchemy  中,对 N+1  问题的常规缓解方法是利用其非常强大的急切加载系统。然而,急切加载要求在前面指定要加载的属性。对于不希望进行延迟加载的其他属性的代码问题,可以使用  raiseload() 策略来解决;此加载器策略用具有信息性错误引发替换了延迟加载的行为:

from sqlalchemy import select
from sqlalchemy.orm import raiseload
stmt = select(User).options(raiseload(User.addresses))

以上,从上述查询中加载的User对象不会加载.addresses集合;如果稍后的一些代码尝试访问此属性,则会引发 ORM 异常

可以使用 raiseload() 与所谓的“通配符”指示符一起使用,以指示所有关系都应使用此策略。例如,要设置仅一个属性作为急切加载,而其他所有属性都作为 raise:

from sqlalchemy import select
from sqlalchemy.orm import joinedload
from sqlalchemy.orm import raiseload
stmt = select(Order).options(joinedload(Order.items), raiseload("*"))

上述通配符将适用于所有关系,而不仅限于 Orderitems 之外,还包括 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 对象设置 raise:

stmt = select(Order).options(joinedload(Order.items).raiseload("*"))

raiseload()选项仅适用于关系属性。对于面向列的属性,defer()选项支持defer.raiseload选项,其工作方式相同。

提示

“raiseload”策略不适用于 unit of work 提交过程中。这意味着如果Session.flush()过程需要加载一个集合以完成其工作,它将通过任何raiseload()指令绕过这样做。

另请参阅

通配符加载策略

使用 raiseload 防止延迟列加载


SqlAlchemy 2.0 中文文档(十九)(4)https://developer.aliyun.com/article/1562934

相关文章
|
4月前
|
SQL 存储 数据库
SqlAlchemy 2.0 中文文档(十九)(2)
SqlAlchemy 2.0 中文文档(十九)
36 2
|
4月前
|
SQL Java Go
SqlAlchemy 2.0 中文文档(十九)(1)
SqlAlchemy 2.0 中文文档(十九)
33 1
|
4月前
|
SQL 前端开发 Go
SqlAlchemy 2.0 中文文档(十八)(4)
SqlAlchemy 2.0 中文文档(十八)
28 1
|
4月前
|
SQL 测试技术 Go
SqlAlchemy 2.0 中文文档(十八)(2)
SqlAlchemy 2.0 中文文档(十八)
23 1
|
4月前
|
SQL 存储 大数据
SqlAlchemy 2.0 中文文档(十八)(1)
SqlAlchemy 2.0 中文文档(十八)
32 1
|
4月前
|
SQL 测试技术 Go
SqlAlchemy 2.0 中文文档(十八)(5)
SqlAlchemy 2.0 中文文档(十八)
28 1
|
4月前
|
SQL 测试技术 Go
SqlAlchemy 2.0 中文文档(十八)(3)
SqlAlchemy 2.0 中文文档(十八)
25 1
|
4月前
|
SQL 存储 测试技术
SqlAlchemy 2.0 中文文档(二十)(3)
SqlAlchemy 2.0 中文文档(二十)
28 1
|
4月前
|
SQL 缓存 API
SqlAlchemy 2.0 中文文档(二十)(5)
SqlAlchemy 2.0 中文文档(二十)
29 1
|
4月前
|
SQL 测试技术 API
SqlAlchemy 2.0 中文文档(二十)(4)
SqlAlchemy 2.0 中文文档(二十)
30 1