web-dev-qa-db-fra.com

Quand dois-je utiliser sqlalchemy back_populate?

Quand j'essaie SQLAlchemy Relation Exemple suivant ce guide: Patterns de relation de base

J'ai ce 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):
    __table= 'parent'
    id = Column(Integer, primary_key=True)
    children = relationship("Child")

class Child(Base):
    __table= '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)

Cela fonctionne bien, mais dans le guide, il est indiqué que le modèle devrait être:

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

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

Pourquoi n'ai-je pas besoin de back_populates ou backref dans mon exemple? Quand devrais-je utiliser l'un ou l'autre?

55
Liqang Lau

Si vous utilisez backref, vous n'avez pas besoin de déclarer la relation dans la deuxième table.

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

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

Si vous utilisez pas avec backref et définissez les relationship séparément, alors si vous n'utilisez pas back_populates, sqlalchemy ne saura pas connecter les relations, de sorte que la modification de l'une modifie également l'autre.

Donc, dans votre exemple, vous avez défini les relationship séparément, mais vous n'avez pas fourni de back_populates _ argument, modifier un champ ne mettrait pas automatiquement à jour l’autre dans votre transaction.

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

Voyez comment cela n’a pas rempli automatiquement le champ children?

Maintenant, si vous fournissez un back_populates argument, sqlalchemy connectera les champs.

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

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

Alors maintenant nous avons

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

Sqlalchemy sait que ces deux champs sont liés maintenant et les mettra à jour au fur et à mesure que l'autre se met à jour. Cela vaut la peine de noter que l'utilisation de backref le fera aussi. En utilisant back_populates est agréable si vous souhaitez définir les relations sur chaque classe, il est donc facile de voir tous les champs en regardant simplement la classe de modèle, au lieu de devoir regarder les autres classes qui définissent des champs via backref.

113
Brendan Abel