Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When do I need to use sqlalchemy back_populates?

When I try SQLAlchemy Relation Example following this guide: Basic Relationship Patterns

I have this code

#!/usr/bin/env python # encoding: utf-8 from sqlalchemy import create_engine from sqlalchemy import Table, Column, Integer, ForeignKey from sqlalchemy.orm import relationship, sessionmaker from sqlalchemy.ext.declarative import declarative_base  engine = create_engine('sqlite:///:memory:', echo=True) Session = sessionmaker(bind=engine) session = Session() Base = declarative_base(bind=engine)  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")  Base.metadata.create_all()  p = Parent() session.add(p) session.commit() c = Child(parent_id=p.id) session.add(c) session.commit() print "children: {}".format(p.children[0].id) print "parent: {}".format(c.parent.id) 

It works well, but in the guide, it says the model should be:

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")** 

Why don't I need back_populates or backref in my example? When should I use one or the other?

like image 239
Liqang Lau Avatar asked Oct 05 '16 09:10

Liqang Lau


People also ask

What does Back_populates mean in SQLAlchemy?

The back_populates argument tells SqlAlchemy which column to link with when it joins the two tables. It allows you to access the linked records as a list with something like Parent.

What is Back_populates?

using back_populates 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.

What is Backref SQLAlchemy?

In Flask-SQLAlchemy, the backref parameter in relationship method allows you to declare a new property under a specified class as seen in the example in their docs: class Person(db.Model): id = db.Column(db.Integer, primary_key=True) name = db.Column(db.String(50)) addresses = db.relationship('Address', backref='person ...

What does SQLAlchemy relationship do?

The relationship function is a part of Relationship API of SQLAlchemy ORM package. It provides a relationship between two mapped classes. This corresponds to a parent-child or associative table relationship.


1 Answers

If you use backref you don't need to declare the relationship on the second table.

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')) 

If you're not using backref, and defining the relationship's separately, then if you don't use back_populates, sqlalchemy won't know to connect the relationships, so that modifying one also modifies the other.

So, in your example, where you've defined the relationship's separately, but didn't provide a back_populates argument, modifying one field wouldn't automatically update the other in your transaction.

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

See how it didn't automatically fill out the children field?

Now, if you supply a back_populates argument, sqlalchemy will connect the fields.

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") 

So now we get

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

Sqlalchemy knows these two fields are related now, and will update each as the other is updated. It's worth noting that using backref will do this, too. Using back_populates is nice if you want to define the relationships on every class, so it's 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.

like image 114
Brendan Abel Avatar answered Oct 22 '22 03:10

Brendan Abel