列加载选项

关于本文档

本节介绍关于列加载的附加选项。使用的映射包括用于存储大型字符串值的列,我们可能希望限制何时加载它们。

查看此页面的 ORM 设置。以下的一些示例将重新定义 Book 映射器以修改一些列定义。

使用列延迟限制加载哪些列

列延迟 是指 ORM 映射的列,当查询该类型的对象时,这些列将从 SELECT 语句中省略。这里的一般原理是性能,在某些情况下,表具有很少使用的列,这些列可能具有较大的数据值,因为在每次查询时完全加载这些列可能会耗费大量时间和/或内存。SQLAlchemy ORM 提供了多种方法来控制实体加载时列的加载。

本节中的大多数示例都说明了 ORM 加载器选项。 这些是传递给 Select.options() 方法的小型构造,该方法属于 Select 对象,当对象被编译为 SQL 字符串时,ORM 会使用这些选项。

使用 load_only() 减少加载的列

当加载对象时,如果已知只会访问少量列,则 load_only() 加载器选项是最方便的选择。此选项接受可变数量的类绑定属性对象,这些对象指示应加载的列映射属性,其中主键之外的所有其他列映射属性将不包含在获取的列中。在下面的示例中,Book 类包含列 .title.summary.cover_photo。使用 load_only(),我们可以指示 ORM 仅预先加载 .title.summary

>>> from sqlalchemy import select
>>> from sqlalchemy.orm import load_only
>>> stmt = select(Book).options(load_only(Book.title, Book.summary))
>>> books = session.scalars(stmt).all()
SELECT book.id, book.title, book.summary FROM book [...] ()
>>> for book in books: ... print(f"{book.title} {book.summary}") 100 Years of Krabby Patties some long summary Sea Catch 22 another long summary The Sea Grapes of Wrath yet another summary A Nut Like No Other some long summary Geodesic Domes: A Retrospective another long summary Rocketry for Squirrels yet another summary

上面,SELECT 语句省略了 .cover_photo 列,仅包含 .title.summary,以及主键列 .id;ORM 通常总是获取主键列,因为这些列是建立行标识所必需的。

加载后,对象通常会对剩余的未加载属性应用 延迟加载 行为,这意味着当首次访问任何未加载属性时,将在当前事务中发出 SQL 语句以加载该值。下面,访问 .cover_photo 会发出 SELECT 语句以加载其值

>>> img_data = books[0].cover_photo
SELECT book.cover_photo AS book_cover_photo FROM book WHERE book.id = ? [...] (1,)

延迟加载始终使用对象处于 持久 状态的 Session 发出。如果对象与任何 Session 分离,则操作失败,并引发异常。

作为访问时延迟加载的替代方案,延迟列也可以配置为在访问时引发信息性异常,而与其附加状态无关。当使用 load_only() 构造时,可以使用 load_only.raiseload 参数指示此行为。有关背景和示例,请参阅 使用 raiseload 防止延迟列加载 部分。

提示

如其他地方所述,使用 异步 I/O (asyncio) 时,延迟加载不可用。

load_only() 与多个实体一起使用

load_only() 将自身限制为在其属性列表中引用的单个实体(目前不允许传递跨越多个实体的属性列表)。在下面的示例中,给定的 load_only() 选项仅适用于 Book 实体。 同样被选中的 User 实体不受影响;在生成的 SELECT 语句中,user_account 的所有列都存在,而对于 book 表,仅存在 book.idbook.title

>>> stmt = select(User, Book).join_from(User, Book).options(load_only(Book.title))
>>> print(stmt)
SELECT user_account.id, user_account.name, user_account.fullname, book.id AS id_1, book.title FROM user_account JOIN book ON user_account.id = book.owner_id

如果我们想将 load_only() 选项应用于 UserBook,我们将使用两个单独的选项

>>> stmt = (
...     select(User, Book)
...     .join_from(User, Book)
...     .options(load_only(User.name), load_only(Book.title))
... )
>>> print(stmt)
SELECT user_account.id, user_account.name, book.id AS id_1, book.title FROM user_account JOIN book ON user_account.id = book.owner_id

使用 defer() 忽略特定列

defer() 加载器选项是 load_only() 的更精细的替代方案,它允许将单个特定列标记为 “不加载”。在下面的示例中,defer() 直接应用于 .cover_photo 列,使所有其他列的行为保持不变

>>> from sqlalchemy.orm import defer
>>> stmt = select(Book).where(Book.owner_id == 2).options(defer(Book.cover_photo))
>>> books = session.scalars(stmt).all()
SELECT book.id, book.owner_id, book.title, book.summary FROM book WHERE book.owner_id = ? [...] (2,)
>>> for book in books: ... print(f"{book.title}: {book.summary}") A Nut Like No Other: some long summary Geodesic Domes: A Retrospective: another long summary Rocketry for Squirrels: yet another summary

load_only() 的情况一样,默认情况下,未加载的列将在使用 延迟加载 访问时自行加载

>>> img_data = books[0].cover_photo
SELECT book.cover_photo AS book_cover_photo FROM book WHERE book.id = ? [...] (4,)

可以在一个语句中使用多个 defer() 选项,以便将多个列标记为延迟。

load_only() 的情况一样,defer() 选项还包括使延迟属性在访问时引发异常而不是延迟加载的功能。这在 使用 raiseload 防止延迟列加载 部分中进行了说明。

使用 raiseload 防止延迟列加载

当使用 load_only()defer() 加载器选项时,标记为对象上延迟的属性具有默认行为,即当首次访问时,将在当前事务中发出 SELECT 语句以加载其值。通常有必要阻止此加载发生,而是在访问属性时引发异常,表明不需要查询数据库以获取此列。一个典型的场景是操作,其中加载的对象包含操作进行所需的所有已知列,然后将其传递到视图层。应捕获视图层中发出的任何进一步的 SQL 操作,以便可以调整预先加载操作以适应预先加载的附加数据,而不是产生额外的延迟加载。

对于此用例,defer()load_only() 选项包括一个布尔参数 defer.raiseload,当设置为 True 时,将导致受影响的属性在访问时引发异常。在下面的示例中,延迟列 .cover_photo 将禁止属性访问

>>> book = session.scalar(
...     select(Book).options(defer(Book.cover_photo, raiseload=True)).where(Book.id == 4)
... )
SELECT book.id, book.owner_id, book.title, book.summary FROM book WHERE book.id = ? [...] (4,)
>>> book.cover_photo Traceback (most recent call last): ... sqlalchemy.exc.InvalidRequestError: 'Book.cover_photo' is not available due to raiseload=True

当使用 load_only() 命名一组特定的非延迟列时,可以使用 load_only.raiseload 参数将 raiseload 行为应用于剩余的列,该参数将应用于所有延迟属性

>>> session.expunge_all()
>>> book = session.scalar(
...     select(Book).options(load_only(Book.title, raiseload=True)).where(Book.id == 5)
... )
SELECT book.id, book.title FROM book WHERE book.id = ? [...] (5,)
>>> book.summary Traceback (most recent call last): ... sqlalchemy.exc.InvalidRequestError: 'Book.summary' is not available due to raiseload=True

注意

尚无法在一个语句中混合使用引用同一实体的 load_only()defer() 选项,以更改某些属性的 raiseload 行为;目前,这样做会产生未定义的属性加载行为。

另请参阅

defer.raiseload 功能是 relationships 可用的相同 “raiseload” 功能的列级别版本。对于 relationships 的 “raiseload”,请参阅本指南的 关系加载技术 部分中的 使用 raiseload 防止不需要的延迟加载

在映射上配置列延迟

defer() 的功能可作为映射列的默认行为使用,这可能适用于不应在每次查询时无条件加载的列。要配置,请使用 mapped_column()mapped_column.deferred 参数。下面的示例说明了 Book 的映射,该映射将默认列延迟应用于 summary.cover_photo

>>> class Book(Base):
...     __tablename__ = "book"
...     id: Mapped[int] = mapped_column(primary_key=True)
...     owner_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
...     title: Mapped[str]
...     summary: Mapped[str] = mapped_column(Text, deferred=True)
...     cover_photo: Mapped[bytes] = mapped_column(LargeBinary, deferred=True)
...
...     def __repr__(self) -> str:
...         return f"Book(id={self.id!r}, title={self.title!r})"

使用上述映射,针对 Book 的查询将自动不包括 summary.cover_photo

>>> book = session.scalar(select(Book).where(Book.id == 2))
SELECT book.id, book.owner_id, book.title FROM book WHERE book.id = ? [...] (2,)

与所有延迟一样,当首次访问加载对象上的延迟属性时,默认行为是它们将 延迟加载 其值

>>> img_data = book.cover_photo
SELECT book.cover_photo AS book_cover_photo FROM book WHERE book.id = ? [...] (2,)

defer()load_only() 加载器选项的情况一样,映射器级别延迟还包括 raiseload 行为的选项,而不是延迟加载,当语句中不存在其他选项时。这允许映射,其中某些列默认情况下不会加载,并且在语句中没有使用显式指令的情况下也永远不会延迟加载。有关如何配置和使用此行为的背景信息,请参阅 配置映射器级别的 “raiseload” 行为 部分。

为命令式映射器、映射的 SQL 表达式使用 deferred()

deferred() 函数是早期、更通用的 “延迟列” 映射指令,它早于 SQLAlchemy 中 mapped_column() 构造的引入。

配置 ORM 映射器时使用 deferred(),并接受任意 SQL 表达式或 Column 对象。因此,它适用于非声明式 命令式映射,将其传递给 map_imperatively.properties 字典

from sqlalchemy import Blob
from sqlalchemy import Column
from sqlalchemy import ForeignKey
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy import Table
from sqlalchemy import Text
from sqlalchemy.orm import registry

mapper_registry = registry()

book_table = Table(
    "book",
    mapper_registry.metadata,
    Column("id", Integer, primary_key=True),
    Column("title", String(50)),
    Column("summary", Text),
    Column("cover_image", Blob),
)


class Book:
    pass


mapper_registry.map_imperatively(
    Book,
    book_table,
    properties={
        "summary": deferred(book_table.c.summary),
        "cover_image": deferred(book_table.c.cover_image),
    },
)

当应以延迟方式加载映射的 SQL 表达式时,也可以使用 deferred() 代替 column_property()

from sqlalchemy.orm import deferred


class User(Base):
    __tablename__ = "user"

    id: Mapped[int] = mapped_column(primary_key=True)
    firstname: Mapped[str] = mapped_column()
    lastname: Mapped[str] = mapped_column()
    fullname: Mapped[str] = deferred(firstname + " " + lastname)

使用 undefer() “急切”加载延迟列

对于配置为默认延迟的映射上的列,undefer() 选项将导致任何通常延迟的列被取消延迟,即与映射的所有其他列一起预先加载。例如,我们可以将 undefer() 应用于 Book.summary 列,该列在之前的映射中指示为延迟

>>> from sqlalchemy.orm import undefer
>>> book = session.scalar(select(Book).where(Book.id == 2).options(undefer(Book.summary)))
SELECT book.id, book.owner_id, book.title, book.summary FROM book WHERE book.id = ? [...] (2,)

Book.summary 列现在已急切加载,并且可以访问,而无需发出额外的 SQL

>>> print(book.summary)
another long summary

分组加载延迟列

通常,当使用 mapped_column(deferred=True) 映射列时,当访问对象上的延迟属性时,将发出 SQL 以仅加载该特定列,而不会加载其他列,即使映射具有其他也标记为延迟的列。在延迟属性是应一次加载的所有属性组的一部分的常见情况下,为了避免为每个属性单独发出 SQL,可以使用 mapped_column.deferred_group 参数,该参数接受任意字符串,该字符串将定义要取消延迟的公共列组

>>> class Book(Base):
...     __tablename__ = "book"
...     id: Mapped[int] = mapped_column(primary_key=True)
...     owner_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
...     title: Mapped[str]
...     summary: Mapped[str] = mapped_column(
...         Text, deferred=True, deferred_group="book_attrs"
...     )
...     cover_photo: Mapped[bytes] = mapped_column(
...         LargeBinary, deferred=True, deferred_group="book_attrs"
...     )
...
...     def __repr__(self) -> str:
...         return f"Book(id={self.id!r}, title={self.title!r})"

使用上述映射,访问 summarycover_photo 都将使用一个 SELECT 语句一次加载两列

>>> book = session.scalar(select(Book).where(Book.id == 2))
SELECT book.id, book.owner_id, book.title FROM book WHERE book.id = ? [...] (2,)
>>> img_data, summary = book.cover_photo, book.summary
SELECT book.summary AS book_summary, book.cover_photo AS book_cover_photo FROM book WHERE book.id = ? [...] (2,)

使用 undefer_group() 按组取消延迟

如果延迟列配置了 mapped_column.deferred_group(如前一节介绍),则可以使用 undefer_group() 选项指示整个组急切加载,并传递要急切加载的组的字符串名称

>>> from sqlalchemy.orm import undefer_group
>>> book = session.scalar(
...     select(Book).where(Book.id == 2).options(undefer_group("book_attrs"))
... )
SELECT book.id, book.owner_id, book.title, book.summary, book.cover_photo FROM book WHERE book.id = ? [...] (2,)

summarycover_photo 都可用,无需额外加载

>>> img_data, summary = book.cover_photo, book.summary

在通配符上取消延迟

大多数 ORM 加载器选项都接受通配符表达式,以 "*" 表示,这表示该选项应应用于所有相关属性。如果映射具有一系列延迟列,则可以通过指示通配符一次取消延迟所有此类列,而无需使用组名称

>>> book = session.scalar(select(Book).where(Book.id == 3).options(undefer("*")))
SELECT book.id, book.owner_id, book.title, book.summary, book.cover_photo FROM book WHERE book.id = ? [...] (3,)

配置映射器级别的 “raiseload” 行为

“raiseload”行为首次在使用 raiseload 阻止延迟列加载中引入,也可以作为默认的映射器级别行为应用,使用 mapped_column.deferred_raiseload 参数,该参数属于 mapped_column()。当使用此参数时,受影响的列在所有情况下都会引发访问异常,除非在查询时使用 undefer()load_only() 显式地“取消延迟”。

>>> class Book(Base):
...     __tablename__ = "book"
...     id: Mapped[int] = mapped_column(primary_key=True)
...     owner_id: Mapped[int] = mapped_column(ForeignKey("user_account.id"))
...     title: Mapped[str]
...     summary: Mapped[str] = mapped_column(Text, deferred=True, deferred_raiseload=True)
...     cover_photo: Mapped[bytes] = mapped_column(
...         LargeBinary, deferred=True, deferred_raiseload=True
...     )
...
...     def __repr__(self) -> str:
...         return f"Book(id={self.id!r}, title={self.title!r})"

使用上述映射,默认情况下 .summary.cover_photo 列是不可加载的。

>>> book = session.scalar(select(Book).where(Book.id == 2))
SELECT book.id, book.owner_id, book.title FROM book WHERE book.id = ? [...] (2,)
>>> book.summary Traceback (most recent call last): ... sqlalchemy.exc.InvalidRequestError: 'Book.summary' is not available due to raiseload=True

只有通过在查询时覆盖其行为,通常使用 undefer()undefer_group(),或者较少使用的 defer(),才能加载这些属性。下面的示例应用了 undefer('*') 来取消延迟所有属性,同时还使用了 填充现有对象 来刷新已加载对象的加载器选项。

>>> book = session.scalar(
...     select(Book)
...     .where(Book.id == 2)
...     .options(undefer("*"))
...     .execution_options(populate_existing=True)
... )
SELECT book.id, book.owner_id, book.title, book.summary, book.cover_photo FROM book WHERE book.id = ? [...] (2,)
>>> book.summary 'another long summary'

将任意 SQL 表达式加载到对象上

正如在 选择 ORM 实体和属性 和其他地方讨论的那样,可以使用 select() 构造来加载结果集中的任意 SQL 表达式。例如,如果我们想要发出一个查询来加载 User 对象,但也包括每个 User 拥有的书籍数量的计数,我们可以使用 func.count(Book.id) 来向查询添加一个“count”列,该查询包括与 Book 的 JOIN 以及 GROUP BY 所有者 ID。这将产生 Row 对象,每个对象包含两个条目,一个用于 User,另一个用于 func.count(Book.id)

>>> from sqlalchemy import func
>>> stmt = select(User, func.count(Book.id)).join_from(User, Book).group_by(Book.owner_id)
>>> for user, book_count in session.execute(stmt):
...     print(f"Username: {user.name}  Number of books: {book_count}")
SELECT user_account.id, user_account.name, user_account.fullname, count(book.id) AS count_1 FROM user_account JOIN book ON user_account.id = book.owner_id GROUP BY book.owner_id [...] ()
Username: spongebob Number of books: 3 Username: sandy Number of books: 3

在上面的示例中,User 实体和“book count”SQL 表达式是分别返回的。然而,一个常见的用例是生成一个仅返回 User 对象的查询,例如可以使用 Session.scalars() 进行迭代,其中 func.count(Book.id) SQL 表达式的结果动态应用于每个 User 实体。最终结果类似于使用 column_property() 将任意 SQL 表达式映射到类的情况,但 SQL 表达式可以在查询时修改。对于这种用例,SQLAlchemy 提供了 with_expression() 加载器选项,当与映射器级别的 query_expression() 指令结合使用时,可以产生此结果。

要将 with_expression() 应用于查询,映射类必须预先配置一个 ORM 映射属性,使用 query_expression() 指令;此指令将在映射类上生成一个属性,该属性适用于接收查询时 SQL 表达式。下面我们向 User 添加一个新的属性 User.book_countUser.book_count 属性是只读的,没有默认值;在已加载的实例上访问它通常会产生 None

>>> from sqlalchemy.orm import query_expression
>>> class User(Base):
...     __tablename__ = "user_account"
...     id: Mapped[int] = mapped_column(primary_key=True)
...     name: Mapped[str]
...     fullname: Mapped[Optional[str]]
...     book_count: Mapped[int] = query_expression()
...
...     def __repr__(self) -> str:
...         return f"User(id={self.id!r}, name={self.name!r}, fullname={self.fullname!r})"

通过在我们的映射中配置 User.book_count 属性,我们可以使用 with_expression() 加载器选项,用 SQL 表达式中的数据填充它,以便在加载每个 User 对象时应用自定义 SQL 表达式。

>>> from sqlalchemy.orm import with_expression
>>> stmt = (
...     select(User)
...     .join_from(User, Book)
...     .group_by(Book.owner_id)
...     .options(with_expression(User.book_count, func.count(Book.id)))
... )
>>> for user in session.scalars(stmt):
...     print(f"Username: {user.name}  Number of books: {user.book_count}")
SELECT count(book.id) AS count_1, user_account.id, user_account.name, user_account.fullname FROM user_account JOIN book ON user_account.id = book.owner_id GROUP BY book.owner_id [...] ()
Username: spongebob Number of books: 3 Username: sandy Number of books: 3

在上面,我们将 func.count(Book.id) 表达式从 select() 构造的 columns 参数中移出,并移入 with_expression() 加载器选项。然后,ORM 将其视为一个特殊的列加载选项,该选项动态应用于语句。

query_expression() 映射具有以下注意事项:

  • 在未使用 with_expression() 填充属性的对象上,对象实例上的属性值将为 None,除非在映射上,query_expression.default_expr 参数设置为默认 SQL 表达式。

  • 除非使用 填充现有对象,否则 with_expression()不会填充到已加载的对象上。下面的示例将不起作用,因为 A 对象已经加载。

    # load the first A
    obj = session.scalars(select(A).order_by(A.id)).first()
    
    # load the same A with an option; expression will **not** be applied
    # to the already-loaded object
    obj = session.scalars(select(A).options(with_expression(A.expr, some_expr))).first()

    要确保属性在现有对象上重新加载,请使用 填充现有对象 执行选项,以确保重新填充所有列。

    obj = session.scalars(
        select(A)
        .options(with_expression(A.expr, some_expr))
        .execution_options(populate_existing=True)
    ).first()
  • 当对象过期时,with_expression() SQL 表达式会丢失。一旦对象过期,无论是通过 Session.expire() 还是通过 Session.commit() 的 expire_on_commit 行为,SQL 表达式及其值不再与属性关联,并在后续访问时返回 None

  • with_expression() 作为对象加载选项,仅在查询的最外层部分生效,并且仅适用于针对完整实体的查询,而不适用于子查询中的任意列选择或复合语句(如 UNION)的元素。请参阅下一节 将 with_expression() 与 UNION 和其他子查询一起使用 以获取示例。

  • 映射的属性不能应用于查询的其他部分,例如 WHERE 子句、ORDER BY 子句,并且不能使用特别的表达式;也就是说,以下方法不起作用:

    # can't refer to A.expr elsewhere in the query
    stmt = (
        select(A)
        .options(with_expression(A.expr, A.x + A.y))
        .filter(A.expr > 5)
        .order_by(A.expr)
    )

    在上面的 WHERE 子句和 ORDER BY 子句中,A.expr 表达式将解析为 NULL。要在整个查询中使用该表达式,请将其赋值给一个变量并使用该变量。

    # assign desired expression up front, then refer to that in
    # the query
    a_expr = A.x + A.y
    stmt = (
        select(A)
        .options(with_expression(A.expr, a_expr))
        .filter(a_expr > 5)
        .order_by(a_expr)
    )

另请参阅

with_expression() 选项是一个特殊选项,用于在查询时动态地将 SQL 表达式应用于映射类。对于在映射器上配置的普通固定 SQL 表达式,请参阅 作为映射属性的 SQL 表达式 部分。

with_expression() 与 UNION 和其他子查询一起使用

with_expression() 构造是一个 ORM 加载器选项,因此只能应用于 SELECT 语句的最外层,该语句旨在加载特定的 ORM 实体。如果它在 select() 中使用,而该 select() 将用作子查询或复合语句(如 UNION)中的元素,则它没有任何效果。

为了在子查询中使用任意 SQL 表达式,应使用正常的 Core 样式添加表达式的方法。要将子查询派生的表达式组装到 ORM 实体的 query_expression() 属性上,with_expression() 在 ORM 对象加载的顶层使用,引用子查询中的 SQL 表达式。

在下面的示例中,针对 ORM 实体 A 使用了两个 select() 构造,并在 expr 中标记了一个额外的 SQL 表达式,并使用 union_all() 组合在一起。然后,在最顶层,从这个 UNION 中 SELECT 了 A 实体,使用了 从 UNION 和其他集合操作中选择实体 中描述的查询技术,并添加了一个带有 with_expression() 的选项,以将此 SQL 表达式提取到新加载的 A 实例上。

>>> from sqlalchemy import union_all
>>> s1 = (
...     select(User, func.count(Book.id).label("book_count"))
...     .join_from(User, Book)
...     .where(User.name == "spongebob")
... )
>>> s2 = (
...     select(User, func.count(Book.id).label("book_count"))
...     .join_from(User, Book)
...     .where(User.name == "sandy")
... )
>>> union_stmt = union_all(s1, s2)
>>> orm_stmt = (
...     select(User)
...     .from_statement(union_stmt)
...     .options(with_expression(User.book_count, union_stmt.selected_columns.book_count))
... )
>>> for user in session.scalars(orm_stmt):
...     print(f"Username: {user.name}  Number of books: {user.book_count}")
SELECT user_account.id, user_account.name, user_account.fullname, count(book.id) AS book_count FROM user_account JOIN book ON user_account.id = book.owner_id WHERE user_account.name = ? UNION ALL SELECT user_account.id, user_account.name, user_account.fullname, count(book.id) AS book_count FROM user_account JOIN book ON user_account.id = book.owner_id WHERE user_account.name = ? [...] ('spongebob', 'sandy')
Username: spongebob Number of books: 3 Username: sandy Number of books: 3

列加载 API

对象名称 描述

defer(key, *addl_attrs, [raiseload])

指示应延迟给定的面向列的属性,例如,在访问之前不加载。

deferred(column, *additional_columns, [group, raiseload, comparator_factory, init, repr, default, default_factory, compare, kw_only, hash, active_history, expire_on_flush, info, doc])

指示一个基于列的映射属性,默认情况下,除非访问,否则不会加载。

load_only(*attrs, [raiseload])

指示对于特定实体,只应加载给定的基于列的属性名称列表;所有其他属性都将被延迟加载。

query_expression([default_expr], *, [repr, compare, expire_on_flush, info, doc])

指示一个从查询时 SQL 表达式填充的属性。

undefer(key, *addl_attrs)

指示应取消延迟给定的面向列的属性,例如,在实体的 SELECT 语句中作为一个整体指定。

undefer_group(name)

指示应取消延迟给定延迟组名称内的列。

with_expression(key, expression)

将临时的 SQL 表达式应用于“延迟表达式”属性。

function sqlalchemy.orm.defer(key: Literal['*'] | QueryableAttribute[Any], *addl_attrs: Literal['*'] | QueryableAttribute[Any], raiseload: bool = False) _AbstractLoad

指示应延迟给定的面向列的属性,例如,在访问之前不加载。

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

例如:

from sqlalchemy.orm import defer

session.query(MyClass).options(
    defer(MyClass.attribute_one), defer(MyClass.attribute_two)
)

要在相关类上指定属性的延迟加载,可以一次指定一个令牌的路径,为链中的每个链接指定加载样式。要使链接的加载样式保持不变,请使用 defaultload()

session.query(MyClass).options(
    defaultload(MyClass.someattr).defer(RelatedClass.some_column)
)

可以使用 Load.options() 一次捆绑与关系相关的多个延迟选项。

select(MyClass).options(
    defaultload(MyClass.someattr).options(
        defer(RelatedClass.some_column),
        defer(RelatedClass.some_other_column),
        defer(RelatedClass.another_column),
    )
)
参数:
  • key – 要延迟的属性。

  • raiseload – 当访问延迟属性时,引发 InvalidRequestError 异常,而不是延迟加载值。用于防止发出不必要的 SQL。

1.4 版本新增功能。

function sqlalchemy.orm.deferred(column: _ORMColumnExprArgument[_T], *additional_columns: _ORMColumnExprArgument[Any], group: str | None = None, raiseload: bool = False, comparator_factory: Type[PropComparator[_T]] | None = None, init: _NoArg | bool = _NoArg.NO_ARG, repr: _NoArg | bool = _NoArg.NO_ARG, default: Any | None = _NoArg.NO_ARG, default_factory: _NoArg | Callable[[], _T] = _NoArg.NO_ARG, compare: _NoArg | bool = _NoArg.NO_ARG, kw_only: _NoArg | bool = _NoArg.NO_ARG, hash: _NoArg | bool | None = _NoArg.NO_ARG, active_history: bool = False, expire_on_flush: bool = True, info: _InfoType | None = None, doc: str | None = None) MappedSQLExpression[_T]

指示一个基于列的映射属性,默认情况下,除非访问,否则不会加载。

当使用 mapped_column() 时,通过使用 mapped_column.deferred 参数,可以实现与 deferred() 构造相同的功能。

参数:
  • *columns – 要映射的列。这通常是一个 Column 对象,但为了支持在同一属性下映射多个列,也支持集合。

  • raiseload

    布尔值,如果为 True,则表示如果将要执行加载操作,则应引发异常。

    1.4 版本新增功能。

其他参数与 column_property() 的参数相同。

function sqlalchemy.orm.query_expression(default_expr: _ORMColumnExprArgument[_T] = <sqlalchemy.sql.elements.Null object>, *, repr: Union[_NoArg, bool] = _NoArg.NO_ARG, compare: Union[_NoArg, bool] = _NoArg.NO_ARG, expire_on_flush: bool = True, info: Optional[_InfoType] = None, doc: Optional[str] = None) MappedSQLExpression[_T]

指示一个从查询时 SQL 表达式填充的属性。

参数:

default_expr – 可选的 SQL 表达式对象,如果在以后没有使用 with_expression() 分配,则将在所有情况下使用该对象。

1.2 版本新增功能。

另请参阅

将任意 SQL 表达式加载到对象上 - 背景和用法示例

function sqlalchemy.orm.load_only(*attrs: Literal['*'] | QueryableAttribute[Any], raiseload: bool = False) _AbstractLoad

指示对于特定实体,只应加载给定的基于列的属性名称列表;所有其他属性都将被延迟加载。

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

示例 - 给定一个类 User,仅加载 namefullname 属性

session.query(User).options(load_only(User.name, User.fullname))

示例 - 给定一个关系 User.addresses -> Address,为 User.addresses 集合指定子查询加载,但在每个 Address 对象上仅加载 email_address 属性

session.query(User).options(
    subqueryload(User.addresses).load_only(Address.email_address)
)

对于具有多个实体的语句,可以使用 Load 构造函数专门引用前导实体。

stmt = (
    select(User, Address)
    .join(User.addresses)
    .options(
        Load(User).load_only(User.name, User.fullname),
        Load(Address).load_only(Address.email_address),
    )
)

当与 populate_existing 执行选项一起使用时,仅会刷新列出的属性。

参数:
  • *attrs – 要加载的属性,所有其他属性都将被延迟加载。

  • raiseload

    当访问延迟属性时,引发 InvalidRequestError 异常,而不是延迟加载值。用于防止发出不必要的 SQL。

    2.0 版本新增功能。

参数:
  • *attrs – 要加载的属性,所有其他属性都将被延迟加载。

  • raiseload

    当访问延迟属性时,引发 InvalidRequestError 异常,而不是延迟加载值。用于防止发出不必要的 SQL。

    2.0 版本新增功能。

function sqlalchemy.orm.undefer(key: Literal['*'] | QueryableAttribute[Any], *addl_attrs: Literal['*'] | QueryableAttribute[Any]) _AbstractLoad

指示应取消延迟给定的面向列的属性,例如,在实体的 SELECT 语句中作为一个整体指定。

通常在映射上将要取消延迟的列设置为 deferred() 属性。

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

示例

# undefer two columns
session.query(MyClass).options(
    undefer(MyClass.col1), undefer(MyClass.col2)
)

# undefer all columns specific to a single class using Load + *
session.query(MyClass, MyOtherClass).options(Load(MyClass).undefer("*"))

# undefer a column on a related object
select(MyClass).options(defaultload(MyClass.items).undefer(MyClass.text))
参数:

key – 要取消延迟的属性。

function sqlalchemy.orm.undefer_group(name: str) _AbstractLoad

指示应取消延迟给定延迟组名称内的列。

要取消延迟的列在映射上设置为 deferred() 属性,并包含一个“group”名称。

例如

session.query(MyClass).options(undefer_group("large_attrs"))

要在相关实体上取消延迟一组属性,可以使用关系加载器选项(如 defaultload())拼出路径。

select(MyClass).options(
    defaultload("someattr").undefer_group("large_attrs")
)
function sqlalchemy.orm.with_expression(key: _AttrType, expression: _ColumnExpressionArgument[Any]) _AbstractLoad

将临时的 SQL 表达式应用于“延迟表达式”属性。

此选项与 query_expression() 映射器级别构造结合使用,该构造指示一个属性,该属性应成为临时 SQL 表达式的目标。

例如:

stmt = select(SomeClass).options(
    with_expression(SomeClass.x_y_expr, SomeClass.x + SomeClass.y)
)

1.2 版本新增功能。

参数:
  • key – 要填充的属性

  • expr – 要应用于属性的 SQL 表达式。

另请参阅

将任意 SQL 表达式加载到对象上 - 背景和用法示例