The imports used for each of the following sections is as follows::
from sqlalchemy import Table, Column, Integer, ForeignKey
- from sqlalchemy.orm import relationship, backref
+ from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
parent_id = Column(Integer, ForeignKey('parent.id'))
To establish a bidirectional relationship in one-to-many, where the "reverse"
-side is a many to one, specify the :paramref:`~.relationship.backref` option::
+side is a many to one, specify an additional :func:`.relationship` and connect
+the two using the :paramref:`.relationship.back_populates` parameter::
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
- children = relationship("Child", backref="parent")
+ children = relationship("Child", back_populates="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
+ parent = relationship("Parent", back_populates="children")
``Child`` will get a ``parent`` attribute with many-to-one semantics.
+Alternatively, the :paramref:`~.relationship.backref` option may be used
+on a single :func:`.relationship` instead of using
+:paramref:`~.relationship.back_populates`::
+
+ class Parent(Base):
+ __tablename__ = 'parent'
+ id = Column(Integer, primary_key=True)
+ children = relationship("Child", backref="parent")
+
+
Many To One
~~~~~~~~~~~~
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
-Bidirectional behavior is achieved by setting
-:paramref:`~.relationship.backref` to the value ``"parents"``, which
-will place a one-to-many collection on the ``Child`` class::
+Bidirectional behavior is achieved by adding a second :func:`.relationship`
+and applying the :paramref:`.relationship.back_populates` parameter
+in both directions::
+
+ class Parent(Base):
+ __tablename__ = 'parent'
+ id = Column(Integer, primary_key=True)
+ child_id = Column(Integer, ForeignKey('child.id'))
+ child = relationship("Child", back_populates="parents")
+
+ class Child(Base):
+ __tablename__ = 'child'
+ id = Column(Integer, primary_key=True)
+ parents = relationship("Parent", back_populates="child")
+
+Alternatively, the :paramref:`~.relationship.backref` parameter
+may be applied to a single :func:`.relationship`, such as ``Parent.child``::
class Parent(Base):
__tablename__ = 'parent'
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
- child = relationship("Child", uselist=False, backref="parent")
+ child = relationship("Child", uselist=False, back_populates="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
parent_id = Column(Integer, ForeignKey('parent.id'))
+ parent = relationship("Child", back_populates="child")
-Or to turn a one-to-many backref into one-to-one, use the :func:`.backref` function
-to provide arguments for the reverse side::
+Or for many-to-one::
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
child_id = Column(Integer, ForeignKey('child.id'))
- child = relationship("Child", backref=backref("parent", uselist=False))
+ child = relationship("Child", back_populates="parent")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
+ parent = relationship("Child", back_populates="child", uselist=False)
+
+As always, the :paramref:`.relationship.backref` and :func:`.backref` functions
+may be used in lieu of the :paramref:`.relationship.back_populates` approach;
+to specify ``uselist`` on a backref, use the :func:`.backref` function::
+
+ from sqlalchemy.orm import backref
+
+ class Parent(Base):
+ __tablename__ = 'parent'
+ id = Column(Integer, primary_key=True)
+ child_id = Column(Integer, ForeignKey('child.id'))
+ child = relationship("Child", backref=backref("parent", uselist=False))
+
.. _relationships_many_to_many:
id = Column(Integer, primary_key=True)
For a bidirectional relationship, both sides of the relationship contain a
-collection. The :paramref:`~.relationship.backref` keyword will automatically use
+collection. Specify using :paramref:`.relationship.back_populates`, and
+for each :func:`.relationship` specify the common association table::
+
+ association_table = Table('association', Base.metadata,
+ Column('left_id', Integer, ForeignKey('left.id')),
+ Column('right_id', Integer, ForeignKey('right.id'))
+ )
+
+ class Parent(Base):
+ __tablename__ = 'left'
+ id = Column(Integer, primary_key=True)
+ children = relationship(
+ "Child",
+ secondary=association_table,
+ back_populates="parents")
+
+ class Child(Base):
+ __tablename__ = 'right'
+ id = Column(Integer, primary_key=True)
+ parents = relationship(
+ "Parent",
+ secondary=association_table,
+ back_populates="children")
+
+When using the :paramref:`~.relationship.backref` parameter instead of
+:paramref:`.relationship.back_populates`, the backref will automatically use
the same :paramref:`~.relationship.secondary` argument for the reverse relationship::
association_table = Table('association', Base.metadata,
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
-The bidirectional version adds backrefs to both relationships::
+As always, the bidirectional version make use of :paramref:`.relationship.back_populates`
+or :paramref:`.relationship.backref`::
class Association(Base):
__tablename__ = 'association'
left_id = Column(Integer, ForeignKey('left.id'), primary_key=True)
right_id = Column(Integer, ForeignKey('right.id'), primary_key=True)
extra_data = Column(String(50))
- child = relationship("Child", backref="parent_assocs")
+ child = relationship("Child", back_populates="parents")
+ parent = relationship("Parent", back_populates="children")
class Parent(Base):
__tablename__ = 'left'
id = Column(Integer, primary_key=True)
- children = relationship("Association", backref="parent")
+ children = relationship("Association", back_populates="parent")
class Child(Base):
__tablename__ = 'right'
id = Column(Integer, primary_key=True)
+ parents = relationship("Association", back_populates="child")
Working with the association pattern in its direct form requires that child
objects are associated with an association instance before being appended to
.. sourcecode:: python+sql
>>> from sqlalchemy import ForeignKey
- >>> from sqlalchemy.orm import relationship, backref
+ >>> from sqlalchemy.orm import relationship
>>> class Address(Base):
... __tablename__ = 'addresses'
... email_address = Column(String, nullable=False)
... user_id = Column(Integer, ForeignKey('users.id'))
...
- ... user = relationship("User", backref=backref('addresses', order_by=id))
+ ... user = relationship("User", back_populates="addresses")
...
... def __repr__(self):
... return "<Address(email_address='%s')>" % self.email_address
+ >>> User.addresses = relationship(
+ ... "Address", order_by=Address.id, back_populates="user")
+
The above class introduces the :class:`.ForeignKey` construct, which is a
directive applied to :class:`.Column` that indicates that values in this
column should be :term:`constrained` to be values present in the named remote
:func:`.relationship` uses the foreign key
relationships between the two tables to determine the nature of
this linkage, determining that ``Address.user`` will be :term:`many to one`.
-A subdirective of :func:`.relationship` called :func:`.backref` is
-placed inside of :func:`.relationship`, providing details about
-the relationship as expressed in reverse, that of a collection of ``Address``
-objects on ``User`` referenced by ``User.addresses``. The reverse
-side of a many-to-one relationship is always :term:`one to many`.
+An additional :func:`.relationship` directive is placed on the
+``User`` mapped class under the attribute ``User.addresses``. In both
+:func:`.relationship` directives, the parameter
+:paramref:`.relationship.back_populates` is assigned to refer to the
+complementary attribute names; by doing so, each :func:`.relationship`
+can make intelligent decision about the same relationship as expressed
+in reverse; on one side, ``Address.user`` refers to a ``User`` instance,
+and on the other side, ``User.addresses`` refers to a list of
+``Address`` instances.
+
+.. note::
+
+ The :paramref:`.relationship.back_populates` parameter is a newer
+ version of a very common SQLAlchemy feature called
+ :paramref:`.relationship.backref`. The :paramref:`.relationship.backref`
+ parameter hasn't gone anywhere and will always remain available!
+ The :paramref:`.relationship.back_populates` is the same thing, except
+ a little more verbose and easier to manipulate. For an overview
+ of the entire topic, see the section :ref:`relationships_backref`.
+
+The reverse side of a many-to-one relationship is always :term:`one to many`.
A full catalog of available :func:`.relationship` configurations
is at :ref:`relationship_patterns`.
as Python expressions in order to produce the actual argument, in the
above case the ``User`` class. The names which are allowed during
this evaluation include, among other things, the names of all classes
-which have been created in terms of the declared base. Below we illustrate creation
-of the same "addresses/user" bidirectional relationship in terms of ``User`` instead of
-``Address``::
-
- class User(Base):
- # ....
- addresses = relationship("Address", order_by="Address.id", backref="user")
+which have been created in terms of the declared base.
See the docstring for :func:`.relationship` for more detail on argument style.
... fullname = Column(String)
... password = Column(String)
...
- ... addresses = relationship("Address", backref='user',
+ ... addresses = relationship("Address", back_populates='user',
... cascade="all, delete, delete-orphan")
...
... def __repr__(self):
... id = Column(Integer, primary_key=True)
... email_address = Column(String, nullable=False)
... user_id = Column(Integer, ForeignKey('users.id'))
+ ... user = relationship("User", back_populates="addresses")
...
... def __repr__(self):
... return "<Address(email_address='%s')>" % self.email_address
:class:`.Column` object is also given its name explicitly, rather than it being
taken from an assigned attribute name.
-Next we define ``BlogPost`` and ``Keyword``, with a :func:`.relationship` linked
-via the ``post_keywords`` table::
+Next we define ``BlogPost`` and ``Keyword``, using complementary
+:func:`.relationship` constructs, each referring to the ``post_keywords``
+table as an association table::
>>> class BlogPost(Base):
... __tablename__ = 'posts'
... body = Column(Text)
...
... # many to many BlogPost<->Keyword
- ... keywords = relationship('Keyword', secondary=post_keywords, backref='posts')
+ ... keywords = relationship('Keyword',
+ ... secondary=post_keywords,
+ ... back_populates='posts')
...
... def __init__(self, headline, body, author):
... self.author = author
...
... id = Column(Integer, primary_key=True)
... keyword = Column(String(50), nullable=False, unique=True)
+ ... posts = relationship('BlogPost',
+ ... secondary=post_keywords,
+ ... back_populates='keywords')
...
... def __init__(self, keyword):
... self.keyword = keyword
``User.posts``, we'd like to be able to filter results further so as not to
load the entire collection. For this we use a setting accepted by
:func:`~sqlalchemy.orm.relationship` called ``lazy='dynamic'``, which
-configures an alternate **loader strategy** on the attribute. To use it on the
-"reverse" side of a :func:`~sqlalchemy.orm.relationship`, we use the
-:func:`~sqlalchemy.orm.backref` function:
+configures an alternate **loader strategy** on the attribute::
.. sourcecode:: python+sql
- >>> from sqlalchemy.orm import backref
- >>> # "dynamic" loading relationship to User
- >>> BlogPost.author = relationship(User, backref=backref('posts', lazy='dynamic'))
+ >>> BlogPost.author = relationship(User, back_populates="posts")
+ >>> User.posts = relationship(BlogPost, back_populates="author", lazy="dynamic")
Create new tables: