1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184
|
.. _relationships_backref:
Using the legacy 'backref' relationship parameter
--------------------------------------------------
.. note:: The :paramref:`_orm.relationship.backref` keyword should be considered
legacy, and use of :paramref:`_orm.relationship.back_populates` with explicit
:func:`_orm.relationship` constructs should be preferred. Using
individual :func:`_orm.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.
.. seealso::
For general information about bidirectional relationships, see the
following sections:
:ref:`tutorial_orm_related_objects` - in the :ref:`unified_tutorial`,
presents an overview of bi-directional relationship configuration
and behaviors using :paramref:`_orm.relationship.back_populates`
:ref:`back_populates_cascade` - notes on bi-directional :func:`_orm.relationship`
behavior regarding :class:`_orm.Session` cascade behaviors.
:paramref:`_orm.relationship.back_populates`
The :paramref:`_orm.relationship.backref` keyword argument on the
:func:`_orm.relationship` construct allows the
automatic generation of a new :func:`_orm.relationship` that will be automatically
be added to the ORM mapping for the related class. It will then be
placed into a :paramref:`_orm.relationship.back_populates` configuration
against the current :func:`_orm.relationship` being configured, with both
:func:`_orm.relationship` constructs referring to each other.
Starting with the following example::
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import declarative_base, relationship
Base = declarative_base()
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String)
addresses = relationship("Address", backref="user")
class Address(Base):
__tablename__ = "address"
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = 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 :paramref:`_orm.relationship.back_populates`
it's equivalent to the following::
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import declarative_base, relationship
Base = declarative_base()
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String)
addresses = relationship("Address", back_populates="user")
class Address(Base):
__tablename__ = "address"
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = 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 :ref:`unified_tutorial`
at :ref:`tutorial_orm_related_objects`.
Backref Default Arguments
~~~~~~~~~~~~~~~~~~~~~~~~~
Since :paramref:`_orm.relationship.backref` generates a whole new
:func:`_orm.relationship`, the generation process by default
will attempt to include corresponding arguments in the new
:func:`_orm.relationship` that correspond to the original arguments.
As an example, below is a :func:`_orm.relationship` that includes a
:ref:`custom join condition <relationship_configure_joins>`
which also includes the :paramref:`_orm.relationship.backref` keyword::
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import declarative_base, relationship
Base = declarative_base()
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = Column(String)
addresses = relationship(
"Address",
primaryjoin=(
"and_(User.id==Address.user_id, Address.email.startswith('tony'))"
),
backref="user",
)
class Address(Base):
__tablename__ = "address"
id = Column(Integer, primary_key=True)
email = Column(String)
user_id = Column(Integer, ForeignKey("user.id"))
When the "backref" is generated, the :paramref:`_orm.relationship.primaryjoin`
condition is copied to the new :func:`_orm.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
:paramref:`_orm.relationship.secondary` parameter that refers to a
many-to-many association table, as well as the "join" arguments
:paramref:`_orm.relationship.primaryjoin` and
:paramref:`_orm.relationship.secondaryjoin`; "backref" is smart enough to know
that these two arguments should also be "reversed" when generating
the opposite side.
Specifying Backref Arguments
~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Lots of other arguments for a "backref" are not implicit, and
include arguments like
:paramref:`_orm.relationship.lazy`,
:paramref:`_orm.relationship.remote_side`,
:paramref:`_orm.relationship.cascade` and
:paramref:`_orm.relationship.cascade_backrefs`. For this case we use
the :func:`.backref` function in place of a string; this will store
a specific set of arguments that will be transferred to the new
:func:`_orm.relationship` when generated::
# <other imports>
from sqlalchemy.orm import backref
class User(Base):
__tablename__ = "user"
id = Column(Integer, primary_key=True)
name = 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 :func:`.backref` function formatted the arguments we gave
it into a form that is interpreted by the receiving :func:`_orm.relationship` as additional
arguments to be applied to the new relationship it creates.
|