特殊的关系持久性模式
原文:
docs.sqlalchemy.org/en/20/orm/relationship_persistence.html
指向自身的行 / 相互依赖的行
这是一种非常特殊的情况,其中 relationship()必须执行一个 INSERT 和一个第二个 UPDATE,以正确填充一行(反之亦然,为了删除而执行一个 UPDATE 和 DELETE,而不违反外键约束)。这两种用例是:
- 一个表包含对自身的外键,而且单个行将具有指向其自身主键的外键值。
- 两个表都包含对另一个表的外键引用,每个表中的一行引用另一个表中的另一行。
例如:
user --------------------------------- user_id name related_user_id 1 'ed' 1
或:
widget entry ------------------------------------------- --------------------------------- widget_id name favorite_entry_id entry_id name widget_id 1 'somewidget' 5 5 'someentry' 1
在第一种情况下,一行指向自身。从技术上讲,使用诸如 PostgreSQL 或 Oracle 之类的序列的数据库可以使用先前生成的值一次性插入行,但是依赖于自增样式主键标识符的数据库不能。relationship()
始终假定在刷新期间以“父/子”模型进行行填充,因此除非直接填充主键/外键列,否则relationship()
需要使用两个语句。
在第二种情况下,“widget”行必须在引用的“entry”行之前插入,但是那个“widget”行的“favorite_entry_id”列在生成“entry”行之前无法设置。在这种情况下,通常无法仅使用两个 INSERT 语句插入“widget”和“entry”行;必须执行 UPDATE 以保持外键约束满足。例外情况是如果外键配置为“延迟至提交”(一些数据库支持的功能),并且标识符是手动填充的(再次基本上绕过relationship()
)。
要启用补充 UPDATE 语句的使用,我们使用relationship.post_update
选项的relationship()
。这指定了在两个行都被 INSERTED 之后应使用 UPDATE 语句创建两行之间的关联;它还导致在发出 DELETE 之前通过 UPDATE 将行解除关联。该标志应该放置在一个关系上,最好是一对多的一侧。以下我们举例说明了一个完整的例子,包括两个ForeignKey
构造:
from sqlalchemy import Integer, ForeignKey from sqlalchemy.orm import mapped_column from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import relationship class Base(DeclarativeBase): pass class Entry(Base): __tablename__ = "entry" entry_id = mapped_column(Integer, primary_key=True) widget_id = mapped_column(Integer, ForeignKey("widget.widget_id")) name = mapped_column(String(50)) class Widget(Base): __tablename__ = "widget" widget_id = mapped_column(Integer, primary_key=True) favorite_entry_id = mapped_column( Integer, ForeignKey("entry.entry_id", name="fk_favorite_entry") ) name = mapped_column(String(50)) entries = relationship(Entry, primaryjoin=widget_id == Entry.widget_id) favorite_entry = relationship( Entry, primaryjoin=favorite_entry_id == Entry.entry_id, post_update=True )
当针对上述配置的结构被刷新时,“widget”行将会插入,但不包括“favorite_entry_id”值,然后所有的“entry”行将被插入,引用父“widget”行,然后一个 UPDATE 语句将填充“widget”表的“favorite_entry_id”列(目前每次一行):
>>> w1 = Widget(name="somewidget") >>> e1 = Entry(name="someentry") >>> w1.favorite_entry = e1 >>> w1.entries = [e1] >>> session.add_all([w1, e1]) >>> session.commit() BEGIN (implicit) INSERT INTO widget (favorite_entry_id, name) VALUES (?, ?) (None, 'somewidget') INSERT INTO entry (widget_id, name) VALUES (?, ?) (1, 'someentry') UPDATE widget SET favorite_entry_id=? WHERE widget.widget_id = ? (1, 1) COMMIT
我们可以指定的另一个配置是在Widget
上提供一个更全面的外键约束,以确保favorite_entry_id
引用的是也引用此Widget
的Entry
。我们可以使用复合外键,如下所示:
from sqlalchemy import ( Integer, ForeignKey, String, UniqueConstraint, ForeignKeyConstraint, ) from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import mapped_column from sqlalchemy.orm import relationship class Base(DeclarativeBase): pass class Entry(Base): __tablename__ = "entry" entry_id = mapped_column(Integer, primary_key=True) widget_id = mapped_column(Integer, ForeignKey("widget.widget_id")) name = mapped_column(String(50)) __table_args__ = (UniqueConstraint("entry_id", "widget_id"),) class Widget(Base): __tablename__ = "widget" widget_id = mapped_column(Integer, autoincrement="ignore_fk", primary_key=True) favorite_entry_id = mapped_column(Integer) name = mapped_column(String(50)) __table_args__ = ( ForeignKeyConstraint( ["widget_id", "favorite_entry_id"], ["entry.widget_id", "entry.entry_id"], name="fk_favorite_entry", ), ) entries = relationship( Entry, primaryjoin=widget_id == Entry.widget_id, foreign_keys=Entry.widget_id ) favorite_entry = relationship( Entry, primaryjoin=favorite_entry_id == Entry.entry_id, foreign_keys=favorite_entry_id, post_update=True, )
上面的映射具有一个复合ForeignKeyConstraint
,连接widget_id
和favorite_entry_id
列。为了确保Widget.widget_id
保持为“自动增量”列,我们在Column
上的autoincrement
参数上指定值"ignore_fk"
,并且在每个relationship()
上,我们必须限制那些被视为外键的列,以用于连接和交叉填充。##可变主键/更新级联
当实体的主键更改时,引用主键的相关项也必须更新。对于强制实施引用完整性的数据库,最佳策略是使用数据库的ON UPDATE CASCADE
功能,以便将主键更改传播到引用的外键 - 在事务完成之前,值不能不同步,除非约束标记为“可延迟”。
强烈建议一个希望使用可变值的自然主键的应用程序使用数据库的ON UPDATE CASCADE
功能。一个说明此功能的示例映射是:
class User(Base): __tablename__ = "user" __table_args__ = {"mysql_engine": "InnoDB"} username = mapped_column(String(50), primary_key=True) fullname = mapped_column(String(100)) addresses = relationship("Address") class Address(Base): __tablename__ = "address" __table_args__ = {"mysql_engine": "InnoDB"} email = mapped_column(String(50), primary_key=True) username = mapped_column( String(50), ForeignKey("user.username", onupdate="cascade") )
在上面的示例中,我们在ForeignKey
对象上说明了onupdate="cascade"
,并且我们还说明了mysql_engine='InnoDB'
设置,在 MySQL 后端上,确保使用支持引用完整性的InnoDB
引擎。在使用 SQLite 时,应启用引用完整性,使用 Foreign Key Support 中描述的配置。
也请参阅
使用 ORM 关系的外键 ON DELETE 级联 - 支持使用关系的 ON DELETE CASCADE
mapper.passive_updates
- 类似Mapper
上的功能
模拟有限的 ON UPDATE CASCADE,没有外键支持
在使用不支持引用完整性的数据库,并且使用具有可变值的自然主键时,SQLAlchemy 提供了一个功能,允许将主键值传播到已引用的外键到有限程度,通过针对立即引用主键列的外键列发出 UPDATE 语句,其值已更改。没有引用完整性功能的主要平台是当使用 MyISAM
存储引擎时的 MySQL,以及当没有使用 PRAGMA foreign_keys=ON
时的 SQLite。Oracle 数据库也不支持 ON UPDATE CASCADE
,但因为它仍然强制执行引用完整性,需要将约束标记为可延迟,以便 SQLAlchemy 可以发出 UPDATE 语句。
通过将 relationship.passive_updates
标志设置为 False
,最好是在一对多或多对多的 relationship()
上。当“更新”不再是“被动”的时候,这表明 SQLAlchemy 将为父对象引用的集合中的对象单独发出 UPDATE 语句,这些对象的主键值会发生变化。这还意味着如果集合尚未在本地存在,集合将被完全加载到内存中。
我们之前使用 passive_updates=False
的映射如下:
class User(Base): __tablename__ = "user" username = mapped_column(String(50), primary_key=True) fullname = mapped_column(String(100)) # passive_updates=False *only* needed if the database # does not implement ON UPDATE CASCADE addresses = relationship("Address", passive_updates=False) class Address(Base): __tablename__ = "address" email = mapped_column(String(50), primary_key=True) username = mapped_column(String(50), ForeignKey("user.username"))
passive_updates=False
的关键限制包括:
- 它的性能远远不及直接数据库的 ON UPDATE CASCADE,因为它需要使用 SELECT 完全预加载受影响的集合,并且还必须发出针对这些值的 UPDATE 语句,它将尝试以“批量”的方式运行,但仍然在 DBAPI 级别上按行运行。
- 该功能无法“级联”超过一个级别。也就是说,如果映射 X 有一个外键引用映射 Y 的主键,但是然后映射 Y 的主键本身是映射 Z 的外键,
passive_updates=False
无法将主键值从Z
级联到X
。 - 仅在关系的多对一方配置
passive_updates=False
将不会产生完全的效果,因为工作单元仅在当前身份映射中搜索可能引用具有变异主键的对象,而不是在整个数据库中搜索。
由于现在除了 Oracle 外,几乎所有数据库都支持 ON UPDATE CASCADE
,因此强烈建议在使用自然且可变的主键值时使用传统的 ON UPDATE CASCADE
支持。## 指向自身的行 / 相互依赖的行
这是一个非常特殊的情况,其中关系(relationship()
)必须执行 INSERT 和第二个 UPDATE,以便正确填充一行(反之亦然,执行 UPDATE 和 DELETE 以删除而不违反外键约束)。这两种用例是:
- 一张表包含一个指向自身的外键,而且一行将具有指向自己主键的外键值。
- 两个表分别包含一个外键引用另一个表,每个表中的一行引用另一个表。
例如:
user --------------------------------- user_id name related_user_id 1 'ed' 1
或者:
widget entry ------------------------------------------- --------------------------------- widget_id name favorite_entry_id entry_id name widget_id 1 'somewidget' 5 5 'someentry' 1
在第一种情况下,一行指向自身。从技术上讲,使用序列(如 PostgreSQL 或 Oracle)的数据库可以使用先前生成的值一次性插入行,但依赖自动增量样式主键标识符的数据库则不能。relationship()
始终假定在刷新期间使用“父/子”模型来填充行,因此除非直接填充主键/外键列,否则 relationship()
需要使用两个语句。
在第二种情况下,“widget”行必须在任何引用的“entry”行之前插入,但然后该“widget”行的“favorite_entry_id”列在生成“entry”行之前不能设置。在这种情况下,通常不可能只使用两个 INSERT 语句插入“widget”和“entry”行;必须执行 UPDATE 以保持外键约束得到满足。异常情况是,如果外键配置为“延迟到提交”(某些数据库支持的功能),并且标识符是手动填充的(再次基本上绕过relationship()
)。
为了启用补充的 UPDATE 语句的使用,我们使用relationship()
的relationship.post_update
选项。这指定在两行都被插入后使用 UPDATE 语句创建两行之间的连接;它还导致在发出 DELETE 之前,通过 UPDATE 将行彼此解除关联。这个标志应该放在其中一个关系上,最好是多对一的关系。下面我们举个完整的例子,包括两个ForeignKey
构造:
from sqlalchemy import Integer, ForeignKey from sqlalchemy.orm import mapped_column from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import relationship class Base(DeclarativeBase): pass class Entry(Base): __tablename__ = "entry" entry_id = mapped_column(Integer, primary_key=True) widget_id = mapped_column(Integer, ForeignKey("widget.widget_id")) name = mapped_column(String(50)) class Widget(Base): __tablename__ = "widget" widget_id = mapped_column(Integer, primary_key=True) favorite_entry_id = mapped_column( Integer, ForeignKey("entry.entry_id", name="fk_favorite_entry") ) name = mapped_column(String(50)) entries = relationship(Entry, primaryjoin=widget_id == Entry.widget_id) favorite_entry = relationship( Entry, primaryjoin=favorite_entry_id == Entry.entry_id, post_update=True )
当针对上述配置刷新结构时,将插入“widget”行,但不包括“favorite_entry_id”值,然后将插入所有“entry”行,引用父“widget”行,然后将“widget”表的“favorite_entry_id”列的 UPDATE 语句(目前一次一行)填充:
>>> w1 = Widget(name="somewidget") >>> e1 = Entry(name="someentry") >>> w1.favorite_entry = e1 >>> w1.entries = [e1] >>> session.add_all([w1, e1]) >>> session.commit() BEGIN (implicit) INSERT INTO widget (favorite_entry_id, name) VALUES (?, ?) (None, 'somewidget') INSERT INTO entry (widget_id, name) VALUES (?, ?) (1, 'someentry') UPDATE widget SET favorite_entry_id=? WHERE widget.widget_id = ? (1, 1) COMMIT
我们可以指定的另一个配置是在 Widget
上提供更全面的外键约束,以确保 favorite_entry_id
指向也指向此 Widget
的 Entry
。我们可以使用复合外键,如下所示:
from sqlalchemy import ( Integer, ForeignKey, String, UniqueConstraint, ForeignKeyConstraint, ) from sqlalchemy.orm import DeclarativeBase from sqlalchemy.orm import mapped_column from sqlalchemy.orm import relationship class Base(DeclarativeBase): pass class Entry(Base): __tablename__ = "entry" entry_id = mapped_column(Integer, primary_key=True) widget_id = mapped_column(Integer, ForeignKey("widget.widget_id")) name = mapped_column(String(50)) __table_args__ = (UniqueConstraint("entry_id", "widget_id"),) class Widget(Base): __tablename__ = "widget" widget_id = mapped_column(Integer, autoincrement="ignore_fk", primary_key=True) favorite_entry_id = mapped_column(Integer) name = mapped_column(String(50)) __table_args__ = ( ForeignKeyConstraint( ["widget_id", "favorite_entry_id"], ["entry.widget_id", "entry.entry_id"], name="fk_favorite_entry", ), ) entries = relationship( Entry, primaryjoin=widget_id == Entry.widget_id, foreign_keys=Entry.widget_id ) favorite_entry = relationship( Entry, primaryjoin=favorite_entry_id == Entry.entry_id, foreign_keys=favorite_entry_id, post_update=True, )
上述映射展示了一个由ForeignKeyConstraint
组成的复合键,连接着 widget_id
和 favorite_entry_id
列。为了确保 Widget.widget_id
仍然是一个“自增”的列,我们在Column
上指定了 Column.autoincrement
的值为 "ignore_fk"
,并且在每个relationship()
上,我们必须限制那些被视为外键的列以进行连接和交叉填充。
可变主键 / 更新级联
当实体的主键发生变化时,引用该主键的相关项也必须进行更新。对于强制执行引用完整性的数据库,最佳策略是使用数据库的 ON UPDATE CASCADE 功能,以便将主键更改传播到引用的外键 - 除非约束被标记为“可延迟”,即不执行直到事务完成,否则值不能在任何时刻不同步。
强烈建议希望使用可变值的自然主键的应用程序使用数据库的 ON UPDATE CASCADE
功能。一个示例映射如下:
class User(Base): __tablename__ = "user" __table_args__ = {"mysql_engine": "InnoDB"} username = mapped_column(String(50), primary_key=True) fullname = mapped_column(String(100)) addresses = relationship("Address") class Address(Base): __tablename__ = "address" __table_args__ = {"mysql_engine": "InnoDB"} email = mapped_column(String(50), primary_key=True) username = mapped_column( String(50), ForeignKey("user.username", onupdate="cascade") )
在上文中,我们在 ForeignKey
对象上说明了 onupdate="cascade"
,并且我们还说明了 mysql_engine='InnoDB'
设置,该设置在 MySQL 后端上确保使用支持引用完整性的 InnoDB
引擎。在使用 SQLite 时,应启用引用完整性,使用 外键支持 中描述的配置。
请参阅
使用 ORM 关系的外键 ON DELETE 级联 - 支持使用关系的 ON DELETE CASCADE
mapper.passive_updates
- Mapper
上的类似功能
模拟有限的无外键支持的 ON UPDATE CASCADE
当使用不支持引用完整性的数据库,并且存在具有可变值的自然主键时,SQLAlchemy 提供了一项功能,以允许在有限范围内传播主键值到已引用的外键,方法是针对立即引用其值已更改的主键列发出 UPDATE 语句来更新外键列。不支持引用完整性功能的主要平台是在使用MyISAM
存储引擎时的 MySQL,以及在未使用PRAGMA foreign_keys=ON
指示的情况下的 SQLite。Oracle 数据库也不支持ON UPDATE CASCADE
,但因为它仍然强制执行引用完整性,所以需要将约束标记为可延迟,以便 SQLAlchemy 可以发出 UPDATE 语句。
通过将relationship.passive_updates
标志设置为False
来启用此功能,最好是在一对多或多对多的relationship()
上。当“更新”不再“被动”时,这表示 SQLAlchemy 将为引用具有更改的主键值的父对象的集合中的对象单独发出 UPDATE 语句。这也意味着如果集合尚未在本地存在,那么集合将完全加载到内存中。
我们以前使用passive_updates=False
的映射如下:
class User(Base): __tablename__ = "user" username = mapped_column(String(50), primary_key=True) fullname = mapped_column(String(100)) # passive_updates=False *only* needed if the database # does not implement ON UPDATE CASCADE addresses = relationship("Address", passive_updates=False) class Address(Base): __tablename__ = "address" email = mapped_column(String(50), primary_key=True) username = mapped_column(String(50), ForeignKey("user.username"))
passive_updates=False
的关键限制包括:
- 它的性能比直接的数据库 ON UPDATE CASCADE 要差得多,因为它需要使用 SELECT 完全预加载受影响的集合,并且还必须针对这些值发出 UPDATE 语句,尽管它将尝试以“批处理”的方式运行,但仍然是在 DBAPI 级别上逐行运行。
- 此功能不能“级联”超过一级。也就是说,如果映射 X 具有一个外键,它引用映射 Y 的主键,但然后映射 Y 的主键本身是对映射 Z 的外键,则
passive_updates=False
不能将主键值从Z
级联更改到X
。 - 仅在关系的多对一一侧上配置
passive_updates=False
将不会产生完全效果,因为工作单元仅通过当前身份映射搜索可能引用具有变异主键的对象,而不是在整个数据库中搜索。
由于几乎所有的数据库现在都支持ON UPDATE CASCADE
,因此强烈建议在使用自然且可变的主键值时使用传统的ON UPDATE CASCADE
支持。
模拟无外键支持的有限 ON UPDATE CASCADE
在使用不支持引用完整性的数据库且存在可变值的自然主键的情况下,SQLAlchemy 提供了一种功能,允许在已经引用了外键的情况下将主键值传播到一个有限程度,通过针对立即引用已更改主键列值的主键列的 UPDATE 语句进行发射。主要没有引用完整性功能的平台是在使用 MyISAM
存储引擎时的 MySQL,以及在不使用 PRAGMA foreign_keys=ON
pragma 的情况下的 SQLite。Oracle 数据库也不支持 ON UPDATE CASCADE
,但由于它仍然强制引用完整性,需要将约束标记为可延迟,以便 SQLAlchemy 可以发出 UPDATE 语句。
通过将 relationship.passive_updates
标志设置为 False
来启用此功能,最好在一对多或多对多的 relationship()
上设置。当“更新”不再是“被动”的时候,这表明 SQLAlchemy 将针对父对象引用的集合中的对象单独发出 UPDATE 语句,而这些对象具有正在更改的主键值。这也意味着,如果集合尚未在本地存在,集合将被完全加载到内存中。
我们之前使用 passive_updates=False
的映射如下所示:
class User(Base): __tablename__ = "user" username = mapped_column(String(50), primary_key=True) fullname = mapped_column(String(100)) # passive_updates=False *only* needed if the database # does not implement ON UPDATE CASCADE addresses = relationship("Address", passive_updates=False) class Address(Base): __tablename__ = "address" email = mapped_column(String(50), primary_key=True) username = mapped_column(String(50), ForeignKey("user.username"))
passive_updates=False
的关键限制包括:
- 它的性能远远不如直接的数据库 ON UPDATE CASCADE,因为它需要使用 SELECT 完全预加载受影响的集合,并且还必须发出针对这些值的 UPDATE 语句,尽管它会尝试以“批量”的方式运行,但仍然在 DBAPI 级别逐行运行。
- 该功能无法“级联”超过一级。也就是说,如果映射 X 有一个外键引用到映射 Y 的主键,但映射 Y 的主键本身是映射 Z 的外键,
passive_updates=False
无法将来自Z
到X
的主键值更改级联。 - 仅在关系的多对一侧配置
passive_updates=False
不会产生完全效果,因为工作单元仅在当前标识映射中搜索可能引用具有突变主键的对象,而不是在整个数据库中搜索。
由于除 Oracle 外的几乎所有数据库现在都支持 ON UPDATE CASCADE
,因此强烈建议在使用自然和可变主键值的情况下使用传统的 ON UPDATE CASCADE
支持。
使用遗留的 ‘backref’ 关系参数
注意
应考虑使用遗留的 relationship.backref
关键字,并且应优先使用明确的 relationship()
构造与 relationship.back_populates
。使用单独的 relationship()
构造提供了诸如 ORM 映射类都将其属性提前包括在类构造时等优点,而不是作为延迟步骤,并且配置更为直观,因为所有参数都是明确的。SQLAlchemy 2.0 中的新 PEP 484 特性还利用了属性在源代码中明确存在而不是使用动态属性生成。
请参见
有关双向关系的一般信息,请参阅以下部分:
与 ORM 相关对象一起工作 - 在 SQLAlchemy 统一教程 中,介绍了使用 relationship.back_populates
进行双向关联配置和行为的概览。
双向关系中保存更新级联的行为 - 关于双向 relationship()
行为在 Session
级联行为方面的注意事项。
relationship.back_populates
在relationship()
构造函数中的relationship.backref
关键字参数允许自动生成一个新的relationship()
,该关系将自动添加到相关类的 ORM 映射中。然后,它将被放置到当前正在配置的relationship()
的relationship.back_populates
配置中,其中两个relationship()
构造相互引用。
以以下示例开始:
from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy.orm import DeclarativeBase, relationship class Base(DeclarativeBase): pass class User(Base): __tablename__ = "user" id = mapped_column(Integer, primary_key=True) name = mapped_column(String) addresses = relationship("Address", backref="user") class Address(Base): __tablename__ = "address" id = mapped_column(Integer, primary_key=True) email = mapped_column(String) user_id = mapped_column(Integer, ForeignKey("user.id"))
以上配置在User
上建立了一个名为User.addresses
的Address
对象集合。它还在Address
上建立了一个.user
属性,该属性将指向父User
对象。使用relationship.back_populates
等效于以下操作:
from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy.orm import DeclarativeBase, relationship class Base(DeclarativeBase): pass class User(Base): __tablename__ = "user" id = mapped_column(Integer, primary_key=True) name = mapped_column(String) addresses = relationship("Address", back_populates="user") class Address(Base): __tablename__ = "address" id = mapped_column(Integer, primary_key=True) email = mapped_column(String) user_id = mapped_column(Integer, ForeignKey("user.id")) user = relationship("User", back_populates="addresses")
User.addresses
和Address.user
关系的行为是以双向方式进行的,表示关系的一侧发生变化会影响另一侧。有关此行为的示例和讨论,请参阅 SQLAlchemy 统一教程的使用 ORM 相关对象部分。
反向引用默认参数
由于relationship.backref
会生成一个全新的relationship()
,默认情况下,生成过程将尝试在新的relationship()
中包含对应于原始参数的相应参数。举例说明,下面是一个包含自定义连接条件的relationship()
,该条件还包括relationship.backref
关键字:
from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy.orm import DeclarativeBase, relationship class Base(DeclarativeBase): pass class User(Base): __tablename__ = "user" id = mapped_column(Integer, primary_key=True) name = mapped_column(String) addresses = relationship( "Address", primaryjoin=( "and_(User.id==Address.user_id, Address.email.startswith('tony'))" ), backref="user", ) class Address(Base): __tablename__ = "address" id = mapped_column(Integer, primary_key=True) email = mapped_column(String) user_id = mapped_column(Integer, ForeignKey("user.id"))
当生成“backref”时,relationship.primaryjoin
条件也被复制到新的relationship()
中:
>>> print(User.addresses.property.primaryjoin) "user".id = address.user_id AND address.email LIKE :email_1 || '%%' >>> >>> print(Address.user.property.primaryjoin) "user".id = address.user_id AND address.email LIKE :email_1 || '%%' >>>
其他可转移的参数包括relationship.secondary
参数,它指的是多对多关联表,以及“join”参数relationship.primaryjoin
和relationship.secondaryjoin
;“backref”足够智能,知道在生成相反的一侧时这两个参数也应该被“翻转”。
指定反向引用参数
很多其他用于“backref”的参数都不是隐含的,包括像relationship.lazy
、relationship.remote_side
、relationship.cascade
和relationship.cascade_backrefs
等参数。对于这种情况,我们使用backref()
函数代替字符串;这将存储一组特定的参数,这些参数将在生成新的relationship()
时传递:
# <other imports> from sqlalchemy.orm import backref class User(Base): __tablename__ = "user" id = mapped_column(Integer, primary_key=True) name = mapped_column(String) addresses = relationship( "Address", backref=backref("user", lazy="joined"), )
在上面的例子中,我们只在Address.user
一侧放置了lazy="joined"
指令,这表示当对Address
进行查询时,应自动执行与User
实体的连接,这将填充每个返回的Address
的.user
属性。 backref()
函数将我们给定的参数格式化成一个由接收的relationship()
解释的形式,作为应用于它创建的新关系的附加参数。
反向引用默认参数
由于relationship.backref
生成了一个全新的relationship()
,默认情况下生成过程将尝试在新的relationship()
中包含与原始参数相对应的参数。例如,下面是一个包含自定义连接条件的relationship()
示例,该连接条件还包括relationship.backref
关键字:
from sqlalchemy import Column, ForeignKey, Integer, String from sqlalchemy.orm import DeclarativeBase, relationship class Base(DeclarativeBase): pass class User(Base): __tablename__ = "user" id = mapped_column(Integer, primary_key=True) name = mapped_column(String) addresses = relationship( "Address", primaryjoin=( "and_(User.id==Address.user_id, Address.email.startswith('tony'))" ), backref="user", ) class Address(Base): __tablename__ = "address" id = mapped_column(Integer, primary_key=True) email = mapped_column(String) user_id = mapped_column(Integer, ForeignKey("user.id"))
当生成“反向引用”时,relationship.primaryjoin
条件也会被复制到新的relationship()
中:
>>> print(User.addresses.property.primaryjoin) "user".id = address.user_id AND address.email LIKE :email_1 || '%%' >>> >>> print(Address.user.property.primaryjoin) "user".id = address.user_id AND address.email LIKE :email_1 || '%%' >>>
可传递的其他参数包括指向多对多关联表的relationship.secondary
参数,以及“join”参数relationship.primaryjoin
和relationship.secondaryjoin
;“反向引用”足够智能,可以知道在生成相反方向时这两个参数也应该“反转”。
指定反向引用参数
“反向引用”的许多其他参数都不是隐式的,包括像relationship.lazy
、relationship.remote_side
、relationship.cascade
和relationship.cascade_backrefs
等参数。对于这种情况,我们使用backref()
函数来代替字符串;这将存储一组特定的参数,这些参数在生成新的relationship()
时将被传递:
# <other imports> from sqlalchemy.orm import backref class User(Base): __tablename__ = "user" id = mapped_column(Integer, primary_key=True) name = mapped_column(String) addresses = relationship( "Address", backref=backref("user", lazy="joined"), )
在上面的例子中,我们只在Address.user
一侧放置了lazy="joined"
指令,这意味着当对Address
进行查询时,应自动执行与User
实体的连接,从而填充每个返回的Address
的.user
属性。backref()
函数将我们给定的参数格式化成一种被接收relationship()
解释为要应用于它创建的新关系的附加参数的形式。
关系 API
对象名称 | 描述 |
backref(name, **kwargs) | 在使用relationship.backref 参数时,提供在生成新的relationship() 时使用的特定参数。 |
dynamic_loader([argument], **kw) | 构造一个动态加载的映射器属性。 |
foreign(expr) | 使用‘foreign’注释对主要连接表达式的部分进行注释。 |
relationship([argument, secondary], *, [uselist, collection_class, primaryjoin, secondaryjoin, back_populates, order_by, backref, overlaps, post_update, cascade, viewonly, init, repr, default, default_factory, compare, kw_only, lazy, passive_deletes, passive_updates, active_history, enable_typechecks, foreign_keys, remote_side, join_depth, comparator_factory, single_parent, innerjoin, distinct_target_key, load_on_pending, query_class, info, omit_join, sync_backref], **kw) | 提供两个映射类之间的关联。 |
remote(expr) | 使用‘remote’注释对主要连接表达式的部分进行注释。 |
function sqlalchemy.orm.relationship(argument: _RelationshipArgumentType[Any] | None = None, secondary: _RelationshipSecondaryArgument | None = None, *, uselist: bool | None = None, collection_class: Type[Collection[Any]] | Callable[[], Collection[Any]] | None = None, primaryjoin: _RelationshipJoinConditionArgument | None = None, secondaryjoin: _RelationshipJoinConditionArgument | None = None, back_populates: str | None = None, order_by: _ORMOrderByArgument = False, backref: ORMBackrefArgument | None = None, overlaps: str | None = None, post_update: bool = False, cascade: str = 'save-update, merge', viewonly: bool = False, init: _NoArg | bool = _NoArg.NO_ARG, repr: _NoArg | bool = _NoArg.NO_ARG, default: _NoArg | _T = _NoArg.NO_ARG, default_factory: _NoArg | Callable[[], _T] = _NoArg.NO_ARG, compare: _NoArg | bool = _NoArg.NO_ARG, kw_only: _NoArg | bool = _NoArg.NO_ARG, lazy: _LazyLoadArgumentType = 'select', passive_deletes: Literal['all'] | bool = False, passive_updates: bool = True, active_history: bool = False, enable_typechecks: bool = True, foreign_keys: _ORMColCollectionArgument | None = None, remote_side: _ORMColCollectionArgument | None = None, join_depth: int | None = None, comparator_factory: Type[RelationshipProperty.Comparator[Any]] | None = None, single_parent: bool = False, innerjoin: bool = False, distinct_target_key: bool | None = None, load_on_pending: bool = False, query_class: Type[Query[Any]] | None = None, info: _InfoType | None = None, omit_join: Literal[None, False] = None, sync_backref: bool | None = None, **kw: Any) → _RelationshipDeclared[Any]
提供两个映射类之间的关联。
这对应于父子或关联表关系。构造的类是Relationship
的一个实例。
另请参阅
使用 ORM 相关对象 - 在 SQLAlchemy 统一教程中对relationship()
进行教程介绍
关系配置 - 叙述性文档
参数:
argument
–
此参数指的是要相关联的类。它接受几种形式,包括对目标类本身的直接引用,目标类的Mapper
实例,将在调用时返回对类或Mapper
的引用的 Python 可调用/ lambda,以及类的字符串名称,这将从正在使用的registry
中解析类,以便找到该类,例如:
class SomeClass(Base): # ... related = relationship("RelatedClass")
relationship.argument
也可以完全省略不在relationship()
构造中传递,而是放置在左侧的Mapped
注释中,如果关系预期为集合,则应包含 Python 集合类型,例如:
class SomeClass(Base): # ... related_items: Mapped[List["RelatedItem"]] = relationship()
- 或者对于多对一或一对一关系:
class SomeClass(Base): # ... related_item: Mapped["RelatedItem"] = relationship()
- 另请参阅
使用声明性定义映射属性 - 在使用声明性时关系配置的更多细节。 secondary
–
对于多对多关系,指定中间表,通常是Table
的一个实例。在较不常见的情况下,参数也可以指定为Alias
构造,甚至是Join
构造。relationship.secondary
可以作为一个可调用函数传递,该函数在映射初始化时进行评估。使用声明性时,它也可以是一个字符串参数,指示存在于与父映射的Table
关联的MetaData
集合中的Table
的名称。
警告
当作为 Python 可评估字符串传递时,使用 Python 的eval()
函数解释该参数。不要将不受信任的输入传递给该字符串。有关声明性评估relationship()
参数的详细信息,请参阅 关系参数的评估 。relationship.secondary
关键字参数通常适用于中间Table
在任何直接类映射中没有其他表达的情况。如果“secondary”表也在其他地方明确映射(例如在关联对象中),则应考虑应用relationship.viewonly
标志,以便这个relationship()
不用于可能与关联对象模式冲突的持久化操作。
另请参阅
多对多 - “多对多”关系的参考示例。
自引用多对多关系 - 在自引用情况下使用多对多的具体细节。
配置多对多关系 - 在使用声明式时的附加选项。
关联对象 - 在组合关联表关系时的一种替代relationship.secondary
的方法,允许在关联表上指定附加属性。
复合“次要”连接 - 一种较少使用的模式,在某些情况下可以使复杂的relationship()
SQL 条件得以使用。active_history=False
– 当为True
时,表示当替换时应加载多对一引用的“先前”值,如果尚未加载。通常,对于简单的多对一引用,历史跟踪逻辑只需要了解“新”值即可执行刷新。此标志适用于使用get_history()
并且还需要知道属性的“先前”值的应用程序。backref
–
引用一个字符串关系名称,或者一个backref()
构造,将被用来自动生成一个新的relationship()
在相关类上,然后使用双向relationship.back_populates
配置来引用这个类。
在现代 Python 中,应优先使用relationship()
和relationship.back_populates
的显式用法,因为在映射器配置和概念上更为健壮直观。它还与 SQLAlchemy 2.0 中引入的新的PEP 484类型特性集成,而动态生成属性则不支持此特性。
另请参阅
使用传统的 ‘backref’ 关系参数 - 关于使用relationship.backref
的注意事项
与 ORM 相关对象的工作 - 在 SQLAlchemy 统一教程中,使用relationship.back_populates
提供了双向关系配置和行为的概述backref()
- 在使用relationship.backref
时允许控制relationship()
的配置。back_populates
–
表示与此类同步的相关类上的relationship()
的名称。通常期望相关类上的relationship()
也参考了这个。这允许每个relationship()
两侧的对象同步 Python 状态变化,并为工作单元刷新过程提供指令,指导沿着这些关系的更改如何持久化。
另请参阅
与 ORM 相关对象的工作 - 在 SQLAlchemy 统一教程中,提供了双向关系配置和行为的概述。
基本关系模式 - 包含了许多relationship.back_populates
的示例。relationship.backref
- 旧形式,允许更简洁的配置,但不支持显式类型化overlaps
–
字符串名称或以逗号分隔的名称集,位于此映射器、后代映射器或目标映射器上,此关系可以与之同时写入相同的外键。此唯一的效果是消除此关系将在持久化时与另一个关系发生冲突的警告。这用于真正可能在写入时与彼此冲突的关系,但应用程序将确保不会发生此类冲突。
新版本 1.4 中新增。
另请参阅
关系 X 将列 Q 复制到列 P,与关系‘Y’冲突 - 用法示例cascade
–
一个逗号分隔的级联规则列表,确定 Session 操作应该如何从父级到子级进行“级联”。默认为False
,表示应该使用默认级联 - 此默认级联为"save-update, merge"
。
可用的级联包括save-update
、merge
、expunge
、delete
、delete-orphan
和refresh-expire
。另一个选项all
表示"save-update, merge, refresh-expire, expunge, delete"
的简写,通常用于指示相关对象应在所有情况下跟随父对象,并在取消关联时删除。
另请参阅
级联 - 每个可用级联选项的详细信息。cascade_backrefs=False
–
旧版本;此标志始终为 False。
在版本 2.0 中更改:“cascade_backrefs” 功能已被移除。collection_class
–
一个类或可调用对象,返回一个新的列表持有对象。将用于代替普通列表存储元素。
另请参阅
自定义集合访问 - 入门文档和示例。comparator_factory
–
一个扩展了Comparator
的类,为比较操作提供自定义 SQL 子句生成。
另请参阅PropComparator
- 在此级别重新定义比较器的一些详细信息。
操作符自定义 - 关于这一特性的简要介绍。distinct_target_key=None
–
指示“子查询”预加载是否应将 DISTINCT 关键字应用于内层 SELECT 语句。当留空时,当目标列不包括目标表的完整主键时,将应用 DISTINCT 关键字。当设置为True
时,DISTINCT 关键字将无条件地应用于内层 SELECT。
当 DISTINCT 降低内层子查询的性能超出重复的内层行可能导致的性能时,将此标志设置为 False 可能是合适的。
另请参阅
关系加载技术 - 包括对子查询预加载的介绍。doc
– 将应用于生成描述符的文档字符串。foreign_keys
–
要在此relationship()
对象的relationship.primaryjoin
条件的上下文中用作“外键”列或引用远程列中的值的列的列表。也就是说,如果此relationship()
的relationship.primaryjoin
条件是a.id == b.a_id
,并且要求b.a_id
中的值在a.id
中存在,则此relationship()
的“外键”列是b.a_id
。
在正常情况下,不需要relationship.foreign_keys
参数。relationship()
将根据那些指定了ForeignKey
的Column
对象或以其他方式列在ForeignKeyConstraint
构造中的引用列的那些列自动确定在relationship.primaryjoin
条件中应被视为“外键”列。只有在以下情况下才需要relationship.foreign_keys
参数:
- 从本地表到远程表的连接可以有多种构造方式,因为存在多个外键引用。设置
foreign_keys
将限制relationship()
仅考虑此处指定的列作为“外键”。- 被映射的
Table
实际上没有ForeignKey
或ForeignKeyConstraint
构造存在,通常是因为该表是从不支持外键反射的数据库(MySQL MyISAM)反射而来。relationship.primaryjoin
参数用于构建非标准的连接条件,该条件使用通常不会引用其“父”列的列或表达式,例如使用 SQL 函数进行的复杂比较表达的连接条件。
- 当
relationship()
构造引发信息性错误消息时,建议使用relationship.foreign_keys
参数,以处理模棱两可的情况。在典型情况下,如果relationship()
没有引发任何异常,则通常不需要relationship.foreign_keys
参数。relationship.foreign_keys
也可以传递为一个在映射器初始化时求值的可调用函数,并且在使用声明性时可以传递为 Python 可评估的字符串。
警告
当作为 Python 可评估的字符串传递时,该参数将使用 Python 的eval()
函数进行解释。不要将不受信任的输入传递给此字符串。有关使用relationship()
参数的声明性评估的详细信息,请参阅关系参数的评估。
另请参阅
处理多个连接路径
创建自定义外键条件foreign()
- 允许在relationship.primaryjoin
条件中直接注释“外键”列。 info
– 可选数据字典,将被填充到此对象的MapperProperty.info
属性中。innerjoin=False
–
当为True
时,连接式急加载将使用内连接而不是外连接来与相关表连接。该选项的目的通常是性能之一,因为内连接通常比外连接执行得更好。
当关系引用通过不可为空的本地外键引用对象时,或者引用为一对一或保证具有一个或至少一个条目的集合时,可以将此标志设置为True
。
该选项支持与joinedload.innerjoin
相同的“嵌套”和“未嵌套”选项。有关嵌套/未嵌套行为的详细信息,请参阅该标志。
另请参阅joinedload.innerjoin
- 由加载器选项指定的选项,包括嵌套行为的详细信息。
应该使用什么类型的加载? - 讨论各种加载器选项的一些细节。join_depth
–
当非None
时,表示“急切”加载器应该在自引用或循环关系上连接多少级深度的整数值。该数字计算相同 Mapper 在加载条件中沿着特定连接分支出现的次数。当保持默认值None
时,急切加载器在遇到已经在链中较高位置的相同目标映射器时将停止链接。此选项适用于连接和子查询急切加载器。
另请参见
配置自引用急切加载 - 入门文档和示例。lazy='select'
–指定相关项目应该如何加载。默认值为select
。值包括:
select
- 当首次访问属性时,应该懒加载项目,使用一个单独的 SELECT 语句,或者对于简单的多对一引用,使用标识映射获取。immediate
- 项目应该在父项加载时加载,使用一个单独的 SELECT 语句,或者对于简单的多对一引用,使用标识映射获取。joined
- 项目应该在与父项相同的查询中“急切”加载,使用 JOIN 或 LEFT OUTER JOIN。JOIN 是“外部”的还是不是由relationship.innerjoin
参数确定。subquery
- 项目应该在父项加载时“急切”加载,使用一个额外的 SQL 语句,为每个请求的集合发出一个 JOIN 到原始语句的子查询。selectin
- 项目应该在父项加载时“急切”加载,使用一个或多个额外的 SQL 语句,发出一个 JOIN 到直接父对象,使用 IN 子句指定主键标识符。noload
- 任何时候都不应发生加载。相关集合将保持为空。不建议一般使用noload
策略。对于一般的“永不加载”方法,请参见仅写关系。raise
- 禁止惰性加载;如果属性的值尚未通过急切加载加载,则访问该属性将引发InvalidRequestError
。当对象在加载后要从其附加的Session
中分离时,可以使用此策略。raise_on_sql
- 禁止发出 SQL 的延迟加载;如果该属性的值尚未通过急加载加载,则访问该属性将引发InvalidRequestError
,“如果延迟加载需要发出 SQL”。如果延迟加载可以从标识映射中提取相关值或确定它应该是 None,则加载该值。当对象将保持与附加的Session
关联时,可以使用此策略,但应阻止附加的额外 SELECT 语句。write_only
- 该属性将配置为具有特殊的“虚拟集合”,该集合可能接收WriteOnlyCollection.add()
和WriteOnlyCollection.remove()
命令以添加或删除单个对象,但绝不会直接从数据库加载或迭代完整对象集。而是提供了诸如WriteOnlyCollection.select()
、WriteOnlyCollection.insert()
、WriteOnlyCollection.update()
和WriteOnlyCollection.delete()
等方法,生成可用于批量加载和修改行的 SQL 构造。用于从不适合一次加载到内存中的大型集合。
当在声明性映射的左侧提供WriteOnlyMapped
注释时,将自动配置write_only
加载程序样式。有关示例,请参阅仅写关系部分。
在版本 2.0 中新增。
另请参阅
仅写关系 - 在 ORM 查询指南中dynamic
- 属性将为所有读操作返回预配置的Query
对象,可以在迭代结果之前应用进一步的过滤操作。
当在声明式映射中的左侧提供了DynamicMapped
注释时,将自动配置dynamic
加载程序样式。有关示例,请参见动态关系加载器一节。
传统功能
“动态”懒加载策略是现在描述的“只写”策略的传统形式,详见仅写关系一节。
另请参见
动态关系加载器 - 在 ORM 查询指南中
仅写关系 - 用于大型集合的更普遍有用的方法,不应完全加载到内存中。- True - ‘select’的同义词
- False - ‘joined’的同义词
- None - ‘noload’的同义词
- 另请参见
关系加载技术 - 在 ORM 查询指南中关于关系加载程序配置的完整文档。 load_on_pending=False
–
指示暂态或挂起父对象的加载行为。
当设置为True
时,会导致惰性加载程序对尚未持久的父对象发出查询,即从未刷新过的父对象。当自动刷新被禁用时,这可能会对挂起对象产生影响,或者对已“附加”到Session
但不属于其挂起集合的暂态对象产生影响。relationship.load_on_pending
标志在 ORM 正常使用时不会改善行为 - 对象引用应在对象级别构造,而不是在外键级别构造,以便它们在刷新进行之前以普通方式存在。此标志不打算供常规使用。
另请参见Session.enable_relationship_loading()
- 此方法为整个对象建立了“在挂起时加载”的行为,还允许在保持为暂态或游离状态的对象上加载。order_by
–
指示加载这些项时应应用的排序。relationship.order_by
预期引用目标类映射到的一个Column
对象之一,或者绑定到引用列的目标类的属性本身。relationship.order_by
还可以作为可调用函数传递,该函数在映射器初始化时进行评估,并且在使用 Declarative 时可以作为 Python 可评估字符串进行传递。
警告
当作为 Python 可评估字符串传递时,该参数将使用 Python 的eval()
函数进行解释。不要将不受信任的输入传递给此字符串。有关relationship()
参数的声明性评估的详细信息,请参阅关系参数的评估。passive_deletes=False
-
指示删除操作期间的加载行为。
True 的值表示在父对象的删除操作期间不应加载未加载的子项目。通常,当删除父项目时,所有子项目都会加载,以便可以将它们标记为已删除,或者将它们的外键设置为 NULL。将此标志标记为 True 通常意味着已经存在一个 ON DELETE 规则,该规则将处理数据库端的更新/删除子行。
此外,将标志设置为字符串值“all”将禁用在父对象被删除且未启用删除或删除-孤儿级联时的“空值”子外键。当数据库端存在触发或错误提升方案时,通常会使用此选项。请注意,在刷新后,会话中的子对象上的外键属性不会更改,因此这是一个非常特殊的用例设置。此外,如果子对象与父对象解除关联,则“nulling out”仍会发生。
另请参阅
使用 ORM 关系的外键 ON DELETE 级联 - 入门文档和示例。passive_updates=True
-
指示当引用的主键值在原位更改时要采取的持久性行为,这表示引用的外键列也需要更改其值。
当为 True 时,假定数据库上的外键已配置为ON UPDATE CASCADE
,并且数据库将处理从源列到依赖行的 UPDATE 传播。当为 False 时,SQLAlchemyrelationship()
构造将尝试发出自己的 UPDATE 语句以修改相关目标。但请注意,SQLAlchemy 无法 对超过一级的级联发出 UPDATE。此外,将此标志设置为 False 在数据库实际强制执行引用完整性的情况下不兼容,除非这些约束明确为“延迟”,如果目标后端支持。
强烈建议使用可变主键的应用程序将passive_updates
设置为 True,并且使用数据库本身的引用完整性功能来高效完全处理更改。
另请参阅
可变主键 / 更新级联 - 介绍文档和示例。mapper.passive_updates
- 类似的标志也适用于连接表继承映射。post_update
–
这表示关系应该在插入后或删除前通过第二个 UPDATE 语句进行处理。该标志用于处理两个单独行之间的双向依赖关系(即每行引用另一行),否则将无法完全插入或删除两行,因为一行在另一行之前存在。当特定的映射安排将导致两行彼此依赖时,请使用此标志,例如,一个表与一组子行之间存在一对多关系,并且还有一个列引用该列表中的单个子行(即两个表相互包含对方的外键)。如果刷新操作返回检测到“循环依赖”错误,这表明您可能希望使用relationship.post_update
来“打破”循环。
另请参阅
指向自身的行 / 相互依赖行 - 介绍文档和示例。primaryjoin
–
将用作子对象与父对象之间的主要连接的 SQL 表达式,或者在多对多关系中将父对象连接到关联表。默认情况下,此值基于父表和子表(或关联表)的外键关系计算。relationship.primaryjoin
也可以作为一个可调用函数传递,该函数在映射器初始化时进行评估,并且在使用声明性时可以作为一个可评估的 Python 字符串进行传递。
警告
当作为一个可评估的 Python 字符串传递时,该参数将使用 Python 的eval()
函数进行解释。不要传递不受信任的输入给此字符串。有关声明性评估relationship()
参数的详细信息,请参阅关系参数的评估。
另请参阅
指定替代连接条件remote_side
–
用于自引用关系,指示形成关系的“远端”的列或列列表。relationship.remote_side
还可以作为可调用函数传递,在映射器初始化时进行评估,并且在使用声明性时可以作为 Python 可评估字符串传递。
警告
当作为 Python 可评估字符串传递时,该参数将使用 Python 的eval()
函数进行解释。不要将不受信任的输入传递给此字符串。有关使用relationship()
参数的声明性评估的详细信息,请参阅关系参数的评估。
另请参阅
邻接列表关系 - 如何配置自引用关系的详细说明,relationship.remote_side
的使用。remote()
- 完成与relationship.remote_side
相同目的的注释函数,通常在使用自定义relationship.primaryjoin
条件时使用。query_class
–Query
的子类,将在由“动态”关系返回的AppenderQuery
内部使用,即指定了lazy="dynamic"
的关系或以其他方式使用了dynamic_loader()
函数构造的关系。
另请参阅
动态关联加载器 - “动态”关联加载器的介绍。secondaryjoin
–
将用作关联表与子对象的连接的 SQL 表达式。默认情况下,此值根据关联和子表的外键关系计算而来。relationship.secondaryjoin
还可以作为可调用函数传递,在映射器初始化时进行评估,并且在使用声明性时可以作为 Python 可评估字符串传递。
警告
当作为 Python 可评估字符串传递时,该参数将使用 Python 的eval()
函数进行解释。不要将不受信任的输入传递给此字符串。有关使用relationship()
参数的声明性评估的详细信息,请参阅关系参数的评估。
另请参阅
指定替代连接条件single_parent
–
当为 True 时,安装一个验证器,该验证器将阻止对象同时与多个父对象关联。这用于应将多对一或多对多关系视为一对一或一对多的情况。除了指定delete-orphan
级联选项的多对一或多对多关系外,其使用是可选的。当要求此选项时,relationship()
构造本身将引发错误指示。
另请参阅
级联操作 - 包括有关何时适合使用relationship.single_parent
标志的详细信息。uselist
–
一个布尔值,指示此属性是否应加载为列表或标量。在大多数情况下,此值由relationship()
在映射配置时自动确定。当使用显式的Mapped
注解时,relationship.uselist
可以根据Mapped
中的注解是否包含集合类来推导出。否则,relationship.uselist
可以从关系的类型和方向推导出 - 一对多形成一个列表,多对一形成一个标量,多对多是一个列表。如果希望在通常存在列表的地方使用标量,例如双向一对一关系,请使用适当的Mapped
注解或将relationship.uselist
设置为 False。relationship.uselist
标志也可用于现有的relationship()
构造,作为一个只读属性,可用于确定此relationship()
是否处理集合或标量属性:
>>> User.addresses.property.uselist True
- 另请参阅
一对一关系 - 介绍了“一对一”关系模式,通常涉及relationship.uselist
的备用设置。 viewonly=False
–
当设置为True
时,该关系仅用于加载对象,而不用于任何持久性操作。指定了relationship.viewonly
的relationship()
可以在relationship.primaryjoin
条件内与更广泛的 SQL 操作一起使用,其中包括使用各种比较运算符以及 SQL 函数,如cast()
。relationship.viewonly
标志在定义任何不代表完整相关对象集的relationship()
时也是一般用途,以防止对集合的修改导致持久性操作。
另见
关于使用视图关系参数的注意事项 - 使用relationship.viewonly
时的最佳实践的更多细节。sync_backref
-
一个布尔值,用于在此关系是relationship.backref
或relationship.back_populates
的目标时启用用于同步 Python 属性的事件。
默认为None
,表示应根据relationship.viewonly
标志的值选择自动值。在其默认状态下,只有在关系的任一方都不是视图时状态变化才会被回填。
版本 1.3.17 中新增。
从版本 1.4 开始:- 指定了relationship.viewonly
的关系自动意味着relationship.sync_backref
为False
。
另见relationship.viewonly
omit_join
-
允许手动控制“selectin”自动连接优化。将其设置为False
以禁用 SQLAlchemy 1.3 中添加的“omit join”功能;或者将其保留为None
以保留自动优化。
注意
此标志只能设置为False
。不需要将其设置为True
,因为“omit_join”优化会自动检测到;如果未检测到,则不支持优化。
在版本 1.3.11 中更改:设置omit_join
为 True 现在会发出警告,因为这不是此标志的预期使用方式。
从版本 1.3 开始新添加。init
– 专门针对声明性数据类映射,指定映射属性是否应作为 dataclass 流程生成的__init__()
方法的一部分。repr
– 专门针对声明性数据类映射,指定映射属性是否应作为 dataclass 流程生成的__repr__()
方法的一部分。default_factory
– 专门针对声明性数据类映射,指定一个默认值生成函数,该函数将作为 dataclass 流程生成的__init__()
方法的一部分进行处理。compare
–
专门针对声明性数据类映射,表示在生成映射类的__eq__()
和__ne__()
方法时,此字段是否应包含在比较操作中。
从版本 2.0.0b4 开始新添加。kw_only
– 专门针对声明性数据类映射,表示在生成__init__()
时此字段是否应标记为关键字参数。
function sqlalchemy.orm.backref(name: str, **kwargs: Any) → ORMBackrefArgument
使用relationship.backref
参数时,提供要在生成新的relationship()
时使用的特定参数。
例如:
'items':relationship( SomeItem, backref=backref('parent', lazy='subquery'))
一般认为relationship.backref
参数是遗留的;对于现代应用程序,应优先使用显式的relationship()
构造,使用relationship.back_populates
参数进行链接。
另请参阅
使用传统的‘backref’关系参数的背景信息,请参阅使用传统的‘backref’关系参数。
function sqlalchemy.orm.dynamic_loader(argument: _RelationshipArgumentType[Any] | None = None, **kw: Any) → RelationshipProperty[Any]
构造一个动态加载的映射器属性。
这与使用relationship()
的lazy='dynamic'
参数基本相同:
dynamic_loader(SomeClass) # is the same as relationship(SomeClass, lazy="dynamic")
更多关于动态加载的详细信息,请参阅动态关系加载器一节。
function sqlalchemy.orm.foreign(expr: _CEA) → _CEA
使用“foreign”注解注释主要联接表达式的一部分。
请参阅创建自定义外键条件一节,了解其用法描述。
另请参阅
创建自定义外键条件
remote()
function sqlalchemy.orm.remote(expr: _CEA) → _CEA
使用“remote”注解注释主要联接表达式的一部分。
参见章节创建自定义外键条件以了解其用法描述。
请参阅也
创建自定义外键条件
foreign()
SqlAlchemy 2.0 中文文档(十五)(2)https://developer.aliyun.com/article/1562980