Concept FAQs

Contributors: Alanna Zhou

backref vs. back_populates vs. none of these

This is introduced when we start using SQLAlchemy, and can be a bit confusing to understand why we need backref or back_populates at all and what the difference between these two are. To help you understand, I am going to break this up into three scenarios:

  1. using neither backref nor back_populates

  2. using back_populates

  3. using backref

Just as a note, we have been using back_populates in our demo and assignment solutions, but that does not mean you can't use backref!

using neither backref nor back_populates

Let's give an example of two classes that have a relationship with each other, Parent and Child. Let's assume that one parent can have multiple children, and each child can only have one parent.

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Child")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))
    parent = relationship("Parent")

This example will still "work", but is not using nor taking advantage of SQLAlchemy's recommended relationship pattern. You can read more about its one-to-many relationship pattern here.

The consequence of this is that if you create child object A and assign it a parent object B, it does not mean that this parent object B will recognize child object A as its child:

>>> parent = Parent()
>>> child = Child()
>>> child.parent = parent
>>> print parent.children
[]

As expected, this is wacky! parent.children should return me the newly created child = Child()!

Let's fix this by using back_populates.

using back_populates

This is a SQLAlchemy keyword that you pass into the relationship() method that allows SQLAlchemy to recognize that there is a connection between the two entities that are related. To modify the previous example, we would do:

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    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")

The way that back_populates works is that you are directing each relationship from one end to the other: Child to parent (lowercase p in parent), and likewise Parent to children).

Now, if you assign some children to a parent, the children will be able to recognize the parent. And if you assign a parent to a child, the parent will be able to recognize the child. By recognize, I am referring to having SQLAlchemy understand that the object is from an existing class you defined.

The fruits of your labor can now be seen:

>>> parent = Parent()
>>> child = Child()
>>> child.parent = parent
>>> print parent.children
[Child(...)]

Solid! But what about backref?

using backref

This is simply another way of doing what back_populates does. There does not seem to be any execution advantage over the other (at least that Alanna knows of, please message her if you discover that that is not the case...). However, we recommend back_populates for a reason that is explained once you've read what exactly back_ref does.

When using backref, you don't need to declare the relationship on the second table defined:

class Parent(Base):
    __tablename__ = 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Child", backref="parent")

class Child(Base):
    __tablename__ = 'child'
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey('parent.id'))

Notice how Child did not have to use relationship nor backref; all it had to do was keep track of the parent.id.

From seeing this, the difference between backref and back_populates is clear. Since you have to define the relationships in every class, we recommend using back_populates because it is nice and easy to see all the fields just be glancing at the model class, instead of having to look at other classes that define fields via backref.

Last updated