使用旧版“backref”关系参数¶
Using the legacy ‘backref’ relationship parameter
备注
relationship.backref
关键字应该视为过时,推荐使用 relationship.back_populates
配合显式的 relationship()
构造。使用单独的 relationship()
构造带来了诸多优势,包括:两个 ORM 映射类会在类构建时一开始就包含它们的属性,而不是作为延迟步骤;配置也更加直观,因为所有参数都是显式的。SQLAlchemy 2.0 中的新 PEP 484 特性也利用了在源代码中显式出现的属性,而不是使用动态属性生成。
参见
有关双向关系的一般信息,请参阅以下章节:
使用 ORM 相关对象 - 在 SQLAlchemy 统一教程 中,介绍了使用 relationship.back_populates
配置和行为的双向关系概述。
具有双向关系的保存-更新级联的行为 - 讨论了双向 relationship()
行为与 Session
级联行为之间的关系。
relationship.backref
关键字参数` 在 relationship()
构造中允许自动生成一个新的 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
上建立了一个 Address
对象的集合,名为 User.addresses
。它还在 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 相关对象。
备注
The relationship.backref
keyword should be considered legacy, and use of relationship.back_populates
with explicit relationship()
constructs should be preferred. Using individual relationship()
constructs provides advantages including that both ORM mapped classes will include their attributes up front as the class is constructed, rather than as a deferred step, and configuration is more straightforward as all arguments are explicit. New PEP 484 features in SQLAlchemy 2.0 also take advantage of attributes being explicitly present in source code rather than using dynamic attribute generation.
参见
For general information about bidirectional relationships, see the following sections:
使用 ORM 相关对象 - in the SQLAlchemy 统一教程, presents an overview of bi-directional relationship configuration and behaviors using relationship.back_populates
具有双向关系的保存-更新级联的行为 - notes on bi-directional relationship()
behavior regarding Session
cascade behaviors.
The relationship.backref
keyword argument on the relationship()
construct allows the automatic generation of a new relationship()
that will be automatically be added to the ORM mapping for the related class. It will then be placed into a relationship.back_populates
configuration against the current relationship()
being configured, with both relationship()
constructs referring to each other.
Starting with the following example:
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"))
The above configuration establishes a collection of Address
objects on User
called User.addresses
. It also establishes a .user
attribute on Address
which will refer to the parent User
object. Using relationship.back_populates
it’s equivalent to the following:
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")
The behavior of the User.addresses
and Address.user
relationships is that they now behave in a bi-directional way, indicating that changes on one side of the relationship impact the other. An example and discussion of this behavior is in the SQLAlchemy 统一教程 at 使用 ORM 相关对象.
Backref 默认参数¶
Backref Default Arguments
由于 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” 足够智能,知道这两个参数在生成对方关系时也应该被“反向”处理。
Since relationship.backref
generates a whole new relationship()
, the generation process by default will attempt to include corresponding arguments in the new relationship()
that correspond to the original arguments. As an example, below is a relationship()
that includes a custom join condition which also includes the relationship.backref
keyword:
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"))
When the “backref” is generated, the relationship.primaryjoin
condition is copied to the new relationship()
as well:
>>> 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 || '%%'
>>>
Other arguments that are transferrable include the relationship.secondary
parameter that refers to a many-to-many association table, as well as the “join” arguments relationship.primaryjoin
and relationship.secondaryjoin
; “backref” is smart enough to know that these two arguments should also be “reversed” when generating the opposite side.
指定 Backref 参数¶
Specifying Backref Arguments
许多其他的 “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()
解释为要应用于它创建的新关系的额外参数。
Lots of other arguments for a “backref” are not implicit, and include arguments like relationship.lazy
, relationship.remote_side
, relationship.cascade
and relationship.cascade_backrefs
. For this case we use the backref()
function in place of a string; this will store a specific set of arguments that will be transferred to the new relationship()
when generated:
# <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"),
)
Where above, we placed a lazy="joined"
directive only on the Address.user
side, indicating that when a query against Address
is made, a join to the User
entity should be made automatically which will populate the .user
attribute of each returned Address
. The backref()
function formatted the arguments we gave it into a form that is interpreted by the receiving relationship()
as additional arguments to be applied to the new relationship it creates.