What is the difference between backref and back_populates in SQLAlchemy?

Photo by Growtika on Unsplash

What is the difference between backref and back_populates in SQLAlchemy?

As I was working on a project I encountered an error when I used back_populates, upon further research I discovered that I made a minor mistake of not using back_populates property correctly. Am writing this to help anyone not to make the same mistake. Let's dive in!

back_populates

When you use back_populates you are supposed to refer to the relationship in both the Parent class and the Child class. This is the mistake I made, I forgot to include the relationship in the Parent class although I included it in the Child class and it got me debugging the entire day.

Example

The following example shows a use case of back_populates:

from sqlalchemy import Column, ForeignKey, Integer
from sqlalchemy.orm import declarative_base, relationship

Base = declarative_base()

class Parent(Base):
    """
    A class representing the 'parent' table.

    Attributes:
        id (int): The primary key of the Parent table.
        children (Relationship): One-to-many relationship with Child table.
    """
    __tablename__ = "parent"
    id = Column(Integer, primary_key=True)

    children = relationship("Child", back_populates="parent")

class Child(Base):
    """
    A class representing the 'child' table.

    Attributes:
        id (int): The primary key of the Child table.
        parent_id (int): Foreign key referencing the Parent table.
        parent (Relationship): Many-to-one relationship with Parent table.
    """
    __tablename__ = "child"
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey("parent.id"))

    parent = relationship("Parent", back_populates="children")

Note: back_populates requires explicit creation of relationship in both Parent and Child classes.

backref

When using backref you only need to create a relationship in one class. The ForeinKey must be included in the Child class regardless of the placement of relationship.

Example

The following example shows a use case of backref:

from sqlalchemy import Column, ForeignKey, Integer
from sqlalchemy.orm import declarative_base, relationship

Base = declarative_base()

class Parent(Base):
    """
    A class representing the 'parent' table.

    Attributes:
        id (int): The primary key of the Parent table.
    """
    __tablename__ = "parent"
    id = Column(Integer, primary_key=True)

class Child(Base):
    """
    A class representing the 'child' table.

    Attributes:
        id (int): The primary key of the Child table.
        parent_id (int): Foreign key referencing the Parent table.
        parent (Relationship): Many-to-one relationship with Parent table.
    """
    __tablename__ = "child"
    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey("parent.id"))

    parent = relationship("Parent", backref="children")

backref is a shortcut for creating a bidirectional relationship between the Parent and the Child class in one place.

Verdict

Both backref and back_populates can be used to establish bidirectional relationships between two tables in an ORM (Object-Relational Mapping) setup. If you only need a simple relationship and don't need to make changes on both sides often, backref might be simpler. If you want more control and explicitness, or if you need to modify both sides frequently, back_populates might be a better choice.

Further reading:

SQLAlchmey Documentation