Using the legacy ‘backref’ relationship parameter

..note:: relationship.backref キーワードはレガシーと考えるべきであり、明示的な relationship() 構文を持つ relationship.back_populates の使用が優先されるべきです。個々の relationship() 構文を使用することは、両方のORMマップされたクラスが、遅延ステップとしてではなく、クラスが構築されるときに事前に属性を含めることを含む利点を提供し、すべての引数が明示的であるため、設定がより簡単になります。SQLAlchemy 2.0の新しい PEP 484 機能も、動的な属性生成を使用するのではなく、ソースコード内に明示的に存在する属性を利用します。

See also

双方向関係の一般的な情報については、次の項を参照してください。

Working with ORM Related Objects - SQLAlchemy Unified Tutorial で、 relationship.back_populates を使用した双方向の関係の設定と動作の概要を示します

Behavior of save-update cascade with bi-directional relationships -Session のカスケード動作に関する、双方向の relationship() の動作についての注意です。

relationship.back_populates

relationship() 構文の relationship.backref キーワード引数を使用すると、関連するクラスのORMマッピングに自動的に追加される新しい relationship() を自動的に生成できます。その後、設定されている現在の relationship() に対して、両方の relationship() 構文が互いを参照しながら、 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", 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.addresses と呼ばれる User 上に Address オブジェクトのコレクションを確立します。また、親の User オブジェクトを参照する Address 上に .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 の関係の動作は、 双方向 の方法で動作するようになりました。これは、関係の一方の側の変更が他方に影響を与えることを示しています。この動作の例と説明は、 Working with ORM Related ObjectsSQLAlchemy Unified Tutorial にあります。

Backref Default Arguments

relationship.backref はまったく新しい relationship() を生成するので、生成プロセスはデフォルトで、元の引数に対応する新しい relationship() に対応する引数を含めようとします。例として、以下は custom join condition を含む 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”は、反対側を生成するときにこれら2つの引数も”反転”する必要があることを十分に理解しています。

Specifying Backref Arguments

“backref”の他の引数の多くは暗黙的ではなく、 relationship.lazyrelationship.remote_siderelationship.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"),
    )

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.

上記では、 lazy="joined" ディレクティブを Address.user 側にのみ配置しました。これは、 Address に対するクエリが作成されたときに、返された各 Address.user 属性を設定する User エンティティへの結合が自動的に行われることを示しています。 backref() 関数は、我々が与えた引数を、それが作成する新しい関係に適用される追加引数として受信側の relationship() によって解釈される形式にフォーマットしました。