使用遗留的 'backref' 关系参数


注意


relationship.backref 关键字应被视为遗留关键字,并且将 relationship.back_populates 与 explicit 一起使用 relationship() 结构。使用单独的 relationship() 结构具有优点,包括两个 ORM 映射类都将在构造类时预先包含其属性,而不是作为延迟步骤,并且由于所有参数都是显式的,因此配置更直接。SQLAlchemy 2.0 中的新 PEP 484 功能还利用了源代码中显式存在的属性,而不是使用动态属性生成。


另请参阅


有关双向关系的一般信息,请参阅以下部分:


使用 ORM 相关对象 - 在 SQLAlchemy Unified Tutorial 中,概述了使用 relationship.back_populates 的双向关系配置和行为


具有双向关系的保存-更新级联的行为 - 有关双向关系的说明() 行为。

relationship.back_populates


relationship.backref 关键字参数 relationship() 结构允许自动生成一个新的 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 上调用 它还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.addressesAddress.user 关系的行为是,它们现在以双向方式运行,这表明关系的一端的更改会影响另一端。此行为的示例和讨论在 SQLAlchemy Unified Tutorial 中 在使用 ORM 相关对象中。


Backref 默认参数


由于 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 condition 也被复制到新的 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.primaryjoinrelationship.secondaryjoin;“backref” 足够聪明,知道在生成相反的 side 时,这两个参数也应该 “相反”。


指定 backref 参数


“backref” 的许多其他参数不是隐含的,并且 include 参数,如 relationship.lazyrelationship.remote_siderelationship.cascaderelationship.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() 解释为要应用于它创建的新关系的附加参数。