SQLAlchemy 2.0 文档
- 上一章: 配置关系连接方式
- 下一章: 集合定制和 API 细节
- 上一级: 主页
- 本页内容
处理大型集合¶
relationship()
的默认行为是基于配置的 加载策略 将集合的内容完全加载到内存中,该策略控制何时以及如何从数据库加载这些内容。相关集合可能不仅在访问时加载到内存中,或者被急切加载,而且在大多数情况下,当集合本身发生变动时,以及当拥有对象将被工作单元系统删除时,都需要进行填充。
当相关集合可能非常大时,在这种情况下将集合填充到内存中可能不可行,因为此操作可能会过度占用时间、网络和内存资源。
本节介绍旨在允许 relationship()
在处理大型集合时保持适当性能的 API 功能。
只写关系¶
只写加载策略是配置 relationship()
的主要方法,该方法将保持可写,但不会将内容加载到内存中。以下是现代类型注释声明式形式下的只写 ORM 配置示例:
>>> from decimal import Decimal
>>> from datetime import datetime
>>> from sqlalchemy import ForeignKey
>>> from sqlalchemy import func
>>> from sqlalchemy.orm import DeclarativeBase
>>> from sqlalchemy.orm import Mapped
>>> from sqlalchemy.orm import mapped_column
>>> from sqlalchemy.orm import relationship
>>> from sqlalchemy.orm import Session
>>> from sqlalchemy.orm import WriteOnlyMapped
>>> class Base(DeclarativeBase):
... pass
>>> class Account(Base):
... __tablename__ = "account"
... id: Mapped[int] = mapped_column(primary_key=True)
... identifier: Mapped[str]
...
... account_transactions: WriteOnlyMapped["AccountTransaction"] = relationship(
... cascade="all, delete-orphan",
... passive_deletes=True,
... order_by="AccountTransaction.timestamp",
... )
...
... def __repr__(self):
... return f"Account(identifier={self.identifier!r})"
>>> class AccountTransaction(Base):
... __tablename__ = "account_transaction"
... id: Mapped[int] = mapped_column(primary_key=True)
... account_id: Mapped[int] = mapped_column(
... ForeignKey("account.id", ondelete="cascade")
... )
... description: Mapped[str]
... amount: Mapped[Decimal]
... timestamp: Mapped[datetime] = mapped_column(default=func.now())
...
... def __repr__(self):
... return (
... f"AccountTransaction(amount={self.amount:.2f}, "
... f"timestamp={self.timestamp.isoformat()!r})"
... )
...
... __mapper_args__ = {"eager_defaults": True}
上面,account_transactions
关系不是使用普通的 Mapped
注释,而是使用 WriteOnlyMapped
类型注释,它在运行时会将 加载策略 设为 lazy="write_only"
,应用于目标 relationship()
。 WriteOnlyMapped
注释是 Mapped
注释的替代形式,表示在对象实例上使用 WriteOnlyCollection
集合类型。
上面的 relationship()
配置还包括几个与当 Account
对象被删除时以及当 AccountTransaction
对象从 account_transactions
集合中移除时要采取的行动有关的元素。这些元素是:
passive_deletes=True
- 允许 工作单元 在删除Account
时无需加载集合;请参阅 在 ORM 关系中使用外键 ON DELETE cascade。ondelete="cascade"
配置在ForeignKey
约束上。这也在 在 ORM 关系中使用外键 ON DELETE cascade 中详细说明。cascade="all, delete-orphan"
- 指示 工作单元 在AccountTransaction
对象从集合中移除时删除它们。请参阅 delete-orphan(在 级联 文档中)。
版本 2.0 中的新功能: 添加了“只写”关系加载器。
创建和持久化新的只写集合¶
只写集合只允许为 瞬态 或 待处理 对象直接分配整个集合。在上面的映射中,这表示我们可以创建一个新的 Account
对象,并附带一系列要添加到 Session
中的 AccountTransaction
对象。任何 Python 可迭代对象都可以用作对象的起始来源,在下面的示例中,我们使用 Python list
>>> new_account = Account(
... identifier="account_01",
... account_transactions=[
... AccountTransaction(description="initial deposit", amount=Decimal("500.00")),
... AccountTransaction(description="transfer", amount=Decimal("1000.00")),
... AccountTransaction(description="withdrawal", amount=Decimal("-29.50")),
... ],
... )
>>> with Session(engine) as session:
... session.add(new_account)
... session.commit()
BEGIN (implicit)
INSERT INTO account (identifier) VALUES (?)
[...] ('account_01',)
INSERT INTO account_transaction (account_id, description, amount, timestamp)
VALUES (?, ?, ?, CURRENT_TIMESTAMP) RETURNING id, timestamp
[... (insertmanyvalues) 1/3 (ordered; batch not supported)] (1, 'initial deposit', 500.0)
INSERT INTO account_transaction (account_id, description, amount, timestamp)
VALUES (?, ?, ?, CURRENT_TIMESTAMP) RETURNING id, timestamp
[insertmanyvalues 2/3 (ordered; batch not supported)] (1, 'transfer', 1000.0)
INSERT INTO account_transaction (account_id, description, amount, timestamp)
VALUES (?, ?, ?, CURRENT_TIMESTAMP) RETURNING id, timestamp
[insertmanyvalues 3/3 (ordered; batch not supported)] (1, 'withdrawal', -29.5)
COMMIT
一旦对象在数据库中持久化(即处于 持久 或 分离 状态),集合就具备了使用新项目进行扩展的能力,以及删除单个项目的能力。但是,集合 **不再能够使用完整替换集合进行重新分配**,因为这样的操作需要将之前的集合完全加载到内存中,以便将旧条目与新条目进行对照。
>>> new_account.account_transactions = [
... AccountTransaction(description="some transaction", amount=Decimal("10.00"))
... ]
Traceback (most recent call last):
...
sqlalchemy.exc.InvalidRequestError: Collection "Account.account_transactions" does not
support implicit iteration; collection replacement operations can't be used
向现有集合添加新项目¶
对于持久对象的只写集合,使用 工作单元 进程进行的集合修改只能使用 WriteOnlyCollection.add()
、WriteOnlyCollection.add_all()
和 WriteOnlyCollection.remove()
方法进行。
>>> from sqlalchemy import select
>>> session = Session(engine, expire_on_commit=False)
>>> existing_account = session.scalar(select(Account).filter_by(identifier="account_01"))
BEGIN (implicit)
SELECT account.id, account.identifier
FROM account
WHERE account.identifier = ?
[...] ('account_01',)
>>> existing_account.account_transactions.add_all(
... [
... AccountTransaction(description="paycheck", amount=Decimal("2000.00")),
... AccountTransaction(description="rent", amount=Decimal("-800.00")),
... ]
... )
>>> session.commit()
INSERT INTO account_transaction (account_id, description, amount, timestamp)
VALUES (?, ?, ?, CURRENT_TIMESTAMP) RETURNING id, timestamp
[... (insertmanyvalues) 1/2 (ordered; batch not supported)] (1, 'paycheck', 2000.0)
INSERT INTO account_transaction (account_id, description, amount, timestamp)
VALUES (?, ?, ?, CURRENT_TIMESTAMP) RETURNING id, timestamp
[insertmanyvalues 2/2 (ordered; batch not supported)] (1, 'rent', -800.0)
COMMIT
上面添加的项目保存在 Session
中的待处理队列中,直到下一次刷新,届时它们将被插入到数据库中,前提是添加的项目之前处于 瞬态 状态。
查询项目¶
WriteOnlyCollection
不会在任何时候存储对集合当前内容的引用,也不会执行直接向数据库发出 SELECT 语句以加载内容的行为;其主要假设是,集合可能包含数千或数百万行,并且不应在任何其他操作的副作用中完全加载到内存中。
相反,WriteOnlyCollection
包含 SQL 生成帮助程序,例如 WriteOnlyCollection.select()
,它将生成一个 Select
结构,该结构预先配置了当前父行的正确 WHERE / FROM 条件,然后可以对其进行进一步修改以选择所需的任何范围的行,以及使用 服务器端游标 等功能来调用,这些功能希望以内存高效的方式遍历整个集合。
生成的语句如下所示。请注意,它还包括 ORDER BY 条件,在示例映射中由 relationship.order_by
参数指示 relationship()
;如果未配置该参数,则会省略此条件。
>>> print(existing_account.account_transactions.select())
SELECT account_transaction.id, account_transaction.account_id, account_transaction.description,
account_transaction.amount, account_transaction.timestamp
FROM account_transaction
WHERE :param_1 = account_transaction.account_id ORDER BY account_transaction.timestamp
我们可以使用此 Select
结构以及 Session
来查询 AccountTransaction
对象,最简单的方法是使用 Session.scalars()
方法,该方法将返回一个 Result
,该方法直接生成 ORM 对象。通常,虽然不是必需的,但 Select
会被进一步修改以限制返回的记录;在下面的示例中,添加了额外的 WHERE 条件以仅加载“借方”账户交易,以及“LIMIT 10”以仅检索前十行。
>>> account_transactions = session.scalars(
... existing_account.account_transactions.select()
... .where(AccountTransaction.amount < 0)
... .limit(10)
... ).all()
BEGIN (implicit)
SELECT account_transaction.id, account_transaction.account_id, account_transaction.description,
account_transaction.amount, account_transaction.timestamp
FROM account_transaction
WHERE ? = account_transaction.account_id AND account_transaction.amount < ?
ORDER BY account_transaction.timestamp LIMIT ? OFFSET ?
[...] (1, 0, 10, 0)
>>> print(account_transactions)
[AccountTransaction(amount=-29.50, timestamp='...'), AccountTransaction(amount=-800.00, timestamp='...')]
删除项目¶
可以使用 WriteOnlyCollection.remove()
方法,将针对当前 Session
在 持久 状态中加载的单个项目标记为从集合中删除。刷新过程将隐式地认为该对象在操作进行时已经是集合的一部分。下面的示例说明了删除单个 AccountTransaction
项目,根据 级联 设置,将导致该行的 DELETE。
>>> existing_transaction = account_transactions[0]
>>> existing_account.account_transactions.remove(existing_transaction)
>>> session.commit()
DELETE FROM account_transaction WHERE account_transaction.id = ?
[...] (3,)
COMMIT
与任何 ORM 映射的集合一样,对象删除可以进行以将对象与集合分离,同时将对象保留在数据库中,或者可以根据 delete-orphan 配置发出其行的 DELETE relationship()
。
新项目的批量 INSERT¶
WriteOnlyCollection
可以生成 DML 结构,例如 Insert
对象,这些对象可以在 ORM 上下文中用于生成批量插入行为。有关 ORM 批量插入的概述,请参阅部分 ORM 批量 INSERT 语句。
一对多集合¶
对于 **仅常规一对多集合**,WriteOnlyCollection.insert()
方法将生成一个 Insert
结构,该结构预先建立了与父对象相对应的 VALUES 条件。由于此 VALUES 条件完全针对相关表,因此该语句可用于 INSERT 新行,这些新行同时将成为相关集合中的新记录。
>>> session.execute(
... existing_account.account_transactions.insert(),
... [
... {"description": "transaction 1", "amount": Decimal("47.50")},
... {"description": "transaction 2", "amount": Decimal("-501.25")},
... {"description": "transaction 3", "amount": Decimal("1800.00")},
... {"description": "transaction 4", "amount": Decimal("-300.00")},
... ],
... )
BEGIN (implicit)
INSERT INTO account_transaction (account_id, description, amount, timestamp) VALUES (?, ?, ?, CURRENT_TIMESTAMP)
[...] [(1, 'transaction 1', 47.5), (1, 'transaction 2', -501.25), (1, 'transaction 3', 1800.0), (1, 'transaction 4', -300.0)]
<...>
>>> session.commit()
COMMIT
多对多集合¶
对于 **多对多集合**,两个类之间的关系涉及一个第三个表,该表使用 relationship.secondary
参数配置 relationship
。要使用 WriteOnlyCollection
将行批量插入到此类型的集合中,可以首先单独批量插入新记录,使用 RETURNING 检索这些记录,然后将这些记录传递给 WriteOnlyCollection.add_all()
方法,工作单元过程将继续将其持久化到集合中。
假设一个类 BankAudit
使用多对多表引用许多 AccountTransaction
记录
>>> from sqlalchemy import Table, Column
>>> audit_to_transaction = Table(
... "audit_transaction",
... Base.metadata,
... Column("audit_id", ForeignKey("audit.id", ondelete="CASCADE"), primary_key=True),
... Column(
... "transaction_id",
... ForeignKey("account_transaction.id", ondelete="CASCADE"),
... primary_key=True,
... ),
... )
>>> class BankAudit(Base):
... __tablename__ = "audit"
... id: Mapped[int] = mapped_column(primary_key=True)
... account_transactions: WriteOnlyMapped["AccountTransaction"] = relationship(
... secondary=audit_to_transaction, passive_deletes=True
... )
为了说明这两个操作,我们使用批量插入添加了更多 AccountTransaction
对象,我们通过将 returning(AccountTransaction)
添加到批量 INSERT 语句来使用 RETURNING 检索这些对象(请注意,我们也可以很容易地使用现有的 AccountTransaction
对象)。
>>> new_transactions = session.scalars(
... existing_account.account_transactions.insert().returning(AccountTransaction),
... [
... {"description": "odd trans 1", "amount": Decimal("50000.00")},
... {"description": "odd trans 2", "amount": Decimal("25000.00")},
... {"description": "odd trans 3", "amount": Decimal("45.00")},
... ],
... ).all()
BEGIN (implicit)
INSERT INTO account_transaction (account_id, description, amount, timestamp) VALUES
(?, ?, ?, CURRENT_TIMESTAMP), (?, ?, ?, CURRENT_TIMESTAMP), (?, ?, ?, CURRENT_TIMESTAMP)
RETURNING id, account_id, description, amount, timestamp
[...] (1, 'odd trans 1', 50000.0, 1, 'odd trans 2', 25000.0, 1, 'odd trans 3', 45.0)
有了准备好的 AccountTransaction
对象列表,WriteOnlyCollection.add_all()
方法用于将多行一次与新的 BankAudit
对象关联。
>>> bank_audit = BankAudit()
>>> session.add(bank_audit)
>>> bank_audit.account_transactions.add_all(new_transactions)
>>> session.commit()
INSERT INTO audit DEFAULT VALUES
[...] ()
INSERT INTO audit_transaction (audit_id, transaction_id) VALUES (?, ?)
[...] [(1, 10), (1, 11), (1, 12)]
COMMIT
项目的批量 UPDATE 和 DELETE¶
与 WriteOnlyCollection
可以生成具有预先建立 WHERE 条件的 Select
结构的方式类似,它还可以生成具有相同 WHERE 条件的 Update
和 Delete
结构,以允许针对大型集合中的元素进行基于条件的 UPDATE 和 DELETE 语句。
一对多集合¶
与 INSERT 一样,此功能在 **一对多集合** 中最直接。
在下面的示例中,WriteOnlyCollection.update()
方法用于生成 UPDATE 语句,该语句针对集合中的元素发出,定位“amount”等于 -800
且向其添加了 200
的金额的行。
>>> session.execute(
... existing_account.account_transactions.update()
... .values(amount=AccountTransaction.amount + 200)
... .where(AccountTransaction.amount == -800),
... )
BEGIN (implicit)
UPDATE account_transaction SET amount=(account_transaction.amount + ?)
WHERE ? = account_transaction.account_id AND account_transaction.amount = ?
[...] (200, 1, -800)
<...>
类似地,WriteOnlyCollection.delete()
将生成一个 DELETE 语句,以相同的方式调用。
>>> session.execute(
... existing_account.account_transactions.delete().where(
... AccountTransaction.amount.between(0, 30)
... ),
... )
DELETE FROM account_transaction WHERE ? = account_transaction.account_id
AND account_transaction.amount BETWEEN ? AND ? RETURNING id
[...] (1, 0, 30)
<...>
多对多集合¶
提示
这里的技术涉及多表 UPDATE 表达式,这稍微高级一些。
对于**多对多集合**的批量 UPDATE 和 DELETE,为了使 UPDATE 或 DELETE 语句与父对象的 primary key 相关联,关联表必须显式地作为 UPDATE/DELETE 语句的一部分,这需要要么后端支持非标准 SQL 语法,要么在构造 UPDATE 或 DELETE 语句时需要额外的显式步骤。
对于支持多表版本的 UPDATE 的后端,WriteOnlyCollection.update()
方法应该可以在没有额外步骤的情况下对多对多集合进行工作,如下面的示例所示,其中 UPDATE 是针对 AccountTransaction
对象发出的,该对象是针对多对多 BankAudit.account_transactions
集合。
>>> session.execute(
... bank_audit.account_transactions.update().values(
... description=AccountTransaction.description + " (audited)"
... )
... )
UPDATE account_transaction SET description=(account_transaction.description || ?)
FROM audit_transaction WHERE ? = audit_transaction.audit_id
AND account_transaction.id = audit_transaction.transaction_id RETURNING id
[...] (' (audited)', 1)
<...>
上面的语句自动使用 SQLite 和其他数据库支持的 “UPDATE..FROM” 语法,在 WHERE 子句中命名额外的 audit_transaction
表。
要 UPDATE 或 DELETE 一个没有提供多表语法的多对多集合,可以使用 SELECT 将多对多条件移动到 SELECT 中,例如,可以与 IN 结合起来匹配行。 WriteOnlyCollection
仍然可以帮助我们,因为我们可以使用 WriteOnlyCollection.select()
方法为我们生成此 SELECT,利用 Select.with_only_columns()
方法生成一个 标量子查询
>>> from sqlalchemy import update
>>> subq = bank_audit.account_transactions.select().with_only_columns(AccountTransaction.id)
>>> session.execute(
... update(AccountTransaction)
... .values(description=AccountTransaction.description + " (audited)")
... .where(AccountTransaction.id.in_(subq))
... )
UPDATE account_transaction SET description=(account_transaction.description || ?)
WHERE account_transaction.id IN (SELECT account_transaction.id
FROM audit_transaction
WHERE ? = audit_transaction.audit_id AND account_transaction.id = audit_transaction.transaction_id)
RETURNING id
[...] (' (audited)', 1)
<...>
只写集合 - API 文档¶
对象名称 | 描述 |
---|---|
只写集合,可以将更改同步到属性事件系统中。 |
|
表示 ORM 映射的属性类型,用于“只写”关系。 |
- class sqlalchemy.orm.WriteOnlyCollection¶
只写集合,可以将更改同步到属性事件系统中。
WriteOnlyCollection
在映射中使用,方法是使用"write_only"
延迟加载策略与relationship()
结合使用。有关此配置的背景信息,请参阅 只写关系。新版本 2.0 中添加。
另请参阅
类签名
class
sqlalchemy.orm.WriteOnlyCollection
(sqlalchemy.orm.writeonly.AbstractCollectionWriter
)-
method
sqlalchemy.orm.WriteOnlyCollection.
add(item: _T) → None¶ 将一个项目添加到
WriteOnlyCollection
中。给定的项目将在下一次刷新时根据父实例的集合持久化到数据库中。
-
method
sqlalchemy.orm.WriteOnlyCollection.
add_all(iterator: Iterable[_T]) → None¶ 将一个可迭代的项目添加到
WriteOnlyCollection
中。给定的项目将在下一次刷新时根据父实例的集合持久化到数据库中。
-
method
sqlalchemy.orm.WriteOnlyCollection.
delete() → Delete¶ 产生一个
Delete
,它将引用实例本地WriteOnlyCollection
中的行。
-
method
sqlalchemy.orm.WriteOnlyCollection.
insert() → Insert¶ 对于一对多集合,产生一个
Insert
,它将在实例本地WriteOnlyCollection
中插入新行。此构造仅支持
Relationship
,该关系**不**包含relationship.secondary
参数。对于引用多对多表的关联关系,请使用普通的批量插入技术来生成新对象,然后使用AbstractCollectionWriter.add_all()
将它们与集合相关联。
-
method
sqlalchemy.orm.WriteOnlyCollection.
remove(item: _T) → None¶ 从
WriteOnlyCollection
中删除一个项目。给定的项目将在下一次刷新时从父实例的集合中删除。
-
method
sqlalchemy.orm.WriteOnlyCollection.
select() → Select[Tuple[_T]]¶ 生成一个
Select
结构,它表示此实例本地WriteOnlyCollection
中的行。
-
method
sqlalchemy.orm.WriteOnlyCollection.
update() → Update¶ 生成一个
Update
,它将根据此实例本地的WriteOnlyCollection
来引用行。
-
method
- class sqlalchemy.orm.WriteOnlyMapped¶
表示 ORM 映射的属性类型,用于“只写”关系。
WriteOnlyMapped
类型注解可以在 带注解的声明式表 映射中使用,以指示应为特定relationship()
使用lazy="write_only"
加载策略。例如:
class User(Base): __tablename__ = "user" id: Mapped[int] = mapped_column(primary_key=True) addresses: WriteOnlyMapped[Address] = relationship( cascade="all,delete-orphan" )
请参阅部分 只写关系 以获取背景信息。
新版本 2.0 中添加。
类签名
class
sqlalchemy.orm.WriteOnlyMapped
(sqlalchemy.orm.base._MappedAnnotationBase
)
动态关系加载器¶
旧版功能
“动态”延迟加载策略是现在在部分 只写关系 中描述的“write_only”策略的旧版形式。
“动态”策略从相关集合中生成一个旧版 Query
对象。但是,“动态”关系的一个主要缺点是,集合将完全迭代的几种情况,其中一些并不明显,这只能通过逐案编程和测试来避免。因此,对于真正的大型集合管理,应优先使用 WriteOnlyCollection
。
动态加载器也不兼容 异步 I/O (asyncio) 扩展。它可以在某些限制下使用,如 Asyncio 动态准则 中所述,但同样应优先使用与 asyncio 完全兼容的 WriteOnlyCollection
。
动态关系策略允许配置一个 relationship()
,当在实例上访问时,它将返回一个旧版 Query
对象来代替集合。然后可以进一步修改 Query
,以便可以根据过滤条件迭代数据库集合。返回的 Query
对象是 AppenderQuery
的一个实例,它结合了 Query
的加载和迭代行为,以及诸如 AppenderQuery.append()
和 AppenderQuery.remove()
之类的基本集合变异方法。
可以使用带类型注解的声明式形式使用 DynamicMapped
注解类来配置“动态”加载策略
from sqlalchemy.orm import DynamicMapped
class User(Base):
__tablename__ = "user"
id: Mapped[int] = mapped_column(primary_key=True)
posts: DynamicMapped[Post] = relationship()
在上面,单个 User
对象上的 User.posts
集合将返回 AppenderQuery
对象,它是 Query
的一个子类,它还支持基本集合变异操作
jack = session.get(User, id)
# filter Jack's blog posts
posts = jack.posts.filter(Post.headline == "this is a post")
# apply array slices
posts = jack.posts[5:20]
动态关系通过 AppenderQuery.append()
和 AppenderQuery.remove()
方法支持有限的写入操作
oldpost = jack.posts.filter(Post.headline == "old post").one()
jack.posts.remove(oldpost)
jack.posts.append(Post("new post"))
由于动态关系的读取端始终查询数据库,因此对底层集合的更改在数据刷新之前将不可见。但是,只要在使用的 Session
上启用了“autoflush”,这将在每次集合即将发出查询时自动发生。
动态关系加载器 - API¶
对象名称 | 描述 |
---|---|
一个支持基本集合存储操作的动态查询。 |
|
表示“动态”关系的 ORM 映射属性类型。 |
- class sqlalchemy.orm.AppenderQuery¶
一个支持基本集合存储操作的动态查询。
AppenderQuery
上的方法包括Query
的所有方法,以及用于集合持久性的其他方法。类签名
class
sqlalchemy.orm.AppenderQuery
(sqlalchemy.orm.dynamic.AppenderMixin
,sqlalchemy.orm.Query
)-
method
sqlalchemy.orm.AppenderQuery.
add(item: _T) → None¶ 继承自
AppenderMixin.add()
方法的AppenderMixin
将一个项目添加到此
AppenderQuery
中。给定的项目将在下一次刷新时根据父实例的集合持久化到数据库中。
提供此方法是为了帮助与
WriteOnlyCollection
集合类保持向前兼容性。新版本 2.0 中添加。
-
method
sqlalchemy.orm.AppenderQuery.
add_all(iterator: Iterable[_T]) → None¶ 继承自
AppenderMixin.add_all()
方法AppenderMixin
将一个可迭代的项目添加到此
AppenderQuery
中。给定的项目将在下一次刷新时根据父实例的集合持久化到数据库中。
提供此方法是为了帮助与
WriteOnlyCollection
集合类保持向前兼容性。新版本 2.0 中添加。
-
method
sqlalchemy.orm.AppenderQuery.
append(item: _T) → None¶ 继承自
AppenderMixin.append()
方法AppenderMixin
将一个项目添加到此
AppenderQuery
中。给定的项目将在下一次刷新时根据父实例的集合持久化到数据库中。
-
method
sqlalchemy.orm.AppenderQuery.
count() → int¶ 继承自
AppenderMixin.count()
方法AppenderMixin
返回此
Query
生成的 SQL 将返回的行数。此方法按如下方式生成此 Query 的 SQL:
SELECT count(1) AS count_1 FROM ( SELECT <rest of query follows...> ) AS anon_1
以上 SQL 返回一行,该行为计数函数的聚合值;
Query.count()
方法将返回该单一整数值。警告
重要的是要注意,
count()
返回的值与此 Query 将从如.all()
方法返回的 ORM 对象的数量不同。当被要求返回完整实体时,Query
对象将根据主键对条目进行去重,这意味着如果同一个主键值在结果中出现多次,则结果中只会有一个该主键的对象。这并不适用于针对单个列的查询。为了对要计数的特定列进行细粒度控制,以跳过子查询的使用或其他控制
FROM
子句,或使用其他聚合函数,请将expression.func
表达式与Session.query()
结合使用,例如:from sqlalchemy import func # count User records, without # using a subquery. session.query(func.count(User.id)) # return count of user "id" grouped # by "name" session.query(func.count(User.id)).\ group_by(User.name) from sqlalchemy import distinct # count distinct "name" values session.query(func.count(distinct(User.name)))
另请参阅
-
method
sqlalchemy.orm.AppenderQuery.
extend(iterator: Iterable[_T]) → None¶ 继承自
AppenderMixin.extend()
方法AppenderMixin
将一个可迭代的项目添加到此
AppenderQuery
中。给定的项目将在下一次刷新时根据父实例的集合持久化到数据库中。
-
method
sqlalchemy.orm.AppenderQuery.
remove(item: _T) → None¶ 继承自
AppenderMixin.remove()
方法AppenderMixin
从此
AppenderQuery
中删除一个项目。给定的项目将在下一次刷新时从父实例的集合中删除。
-
method
- class sqlalchemy.orm.DynamicMapped¶
表示“动态”关系的 ORM 映射属性类型。
在 注释声明式表 映射中,可以使用
DynamicMapped
类型注释来表示对特定relationship()
应该使用lazy="dynamic"
加载器策略。旧版功能
“动态”延迟加载策略是现在在部分 只写关系 中描述的“write_only”策略的旧版形式。
例如:
class User(Base): __tablename__ = "user" id: Mapped[int] = mapped_column(primary_key=True) addresses: DynamicMapped[Address] = relationship( cascade="all,delete-orphan" )
有关背景信息,请参见 动态关系加载器 部分。
新版本 2.0 中添加。
类签名
class
sqlalchemy.orm.DynamicMapped
(sqlalchemy.orm.base._MappedAnnotationBase
)
设置 RaiseLoad¶
当属性通常会发出延迟加载时,“raise”加载的关系将引发 InvalidRequestError
class MyClass(Base):
__tablename__ = "some_table"
# ...
children: Mapped[List[MyRelatedClass]] = relationship(lazy="raise")
在上面的示例中,如果 children
集合的属性访问没有被预先填充,则会引发异常。这包括读取访问,但也适用于集合的写入访问,因为集合只有在先加载它们之后才能被修改。这样做是为了确保应用程序在特定上下文中不会发出任何意外的延迟加载。与必须阅读 SQL 日志以确定所有必要的属性是否被急切加载不同,“raise”策略将导致在访问未加载的属性时立即引发异常。“raise”策略也适用于使用 raiseload()
加载器选项的查询选项。
使用被动删除¶
SQLAlchemy 中集合管理的一个重要方面是,当删除引用集合的对象时,SQLAlchemy 需要考虑此集合中的对象。这些对象需要与父对象分离,对于一对多集合而言,这意味着将外键列设置为 NULL,或者根据 级联 设置,可能希望发出这些行的 DELETE 操作。
工作单元流程仅逐行处理对象,这意味着 DELETE 操作意味着必须在刷新过程中将集合中的所有行完全加载到内存中。对于大型集合,这不可行,因此我们改为依靠数据库本身的能力,使用外键 ON DELETE 规则自动更新或删除行,指示工作单元无需实际加载这些行即可处理它们。可以通过配置 relationship.passive_deletes
在 relationship()
结构上指示工作单元以这种方式工作;使用的外键约束也必须正确配置。
有关完整“被动删除”配置的更多详细信息,请参阅部分 使用外键 ON DELETE 级联与 ORM 关系。
flambé! the dragon and The Alchemist image designs created and generously donated by Rotem Yaari.
使用 Sphinx 7.2.6 创建。文档最后生成时间:2024 年 11 月 8 日星期五上午 08:41:19 EST