언제 sqlalchemy back_populates를 사용해야합니까?


83

이 가이드에 따라 SQLAlchemy 관계 예제를 시도 할 때 : 기본 관계 패턴

이 코드가 있습니다

#!/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)

잘 작동하지만 가이드에서는 모델이 다음과 같아야한다고 말합니다.

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

이유는 필요하지 않습니다 back_populates또는 backref내 예? 둘 중 하나를 언제 사용해야합니까?

답변:


160

사용 backref하는 경우 두 번째 테이블에서 관계를 선언 할 필요가 없습니다.

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

을 사용 하지 않고 의를 별도로 backref정의하는 relationship경우 사용하지 않으면back_populates 경우을 sqlalchemy가 관계를 연결하는 것을 알지 못하므로 하나를 수정하면 다른 것도 수정됩니다.

따라서 relationship의를 별도로 정의 했지만 back_populates인수를 제공하지 않은 예에서 한 필드를 수정해도 트랜잭션에서 다른 필드가 자동으로 업데이트되지 않습니다.

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

어떻게 자동으로 채워지지 않았는지 확인하십시오. children 필드를 보셨나요?

이제 back_populates인수 를 제공하면 sqlalchemy가 필드를 연결합니다.

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

이제 우리는

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

Sqlalchemy는이 두 필드가 현재 관련되어 있다는 것을 알고 있으며 다른 필드가 업데이트되면 각각 업데이트됩니다. 사용 backref하면이 작업도 수행 된다는 점에 주목할 가치가 있습니다. back_populates모든 클래스에 대한 관계를 정의하려는 경우 사용하는 것이 좋습니다. 따라서 backref를 통해 필드를 정의하는 다른 클래스를 볼 필요없이 모든 필드가 모델 클래스를 훑어 보는 것을 쉽게 볼 수 있습니다.


48
back_populatesvs backref: 에 대한 메모는 backref두 클래스 모두에서 관계를 선언 할 필요가 없기 때문에 더 간결하지만 실제로는 이것을 온라인에 저장할 가치가 없습니다. back_populates파이썬 문화에서 "명시적인 것이 암시적인 것보다 낫다" (Zen of Python)뿐만 아니라 많은 모델이있을 때 그 선언을 한 눈에 볼 수 있기 때문에 더 낫다고 생각 합니다. 모든 관련 모델. 또한,의 좋은 측면 혜택은 back_populates대부분의 IDE =)에 자동 완성 양쪽 방향에서 얻을 수 있다는 것입니다
파비아누

backref는 구현하기가 더 쉬울 수 있습니다 (특히 주석을 사용하여 두 클래스의 관계를 명확하게 나타내면 적어도 저는 그렇게 생각했습니다 ...). 단일 테이블에 대한 다중 관계를 구현하고 컨테이너로 작업해야 할 때까지. 결국 back_populates는 코드를 이해하기 쉽게 만듭니다.
Rhdr

는 IS parent_id정말 필요한 아래의 아이? 그리고 문서에
습니까

1
@LuizTauffer parent_id부모-자식 관계를 저장하는 실제 외래 키 필드입니다. 필요합니다. 도우미 테이블은 다 대다 관계를 정의하기위한 것입니다 (예 : 자식에 둘 이상의 부모가있을 수있는 경우). 위의 fkey 예는 각 하위에 하나의 상위 만 있고 상위에 여러 하위가있을 수있는 고전적인 일대 다 예입니다.
Brendan Abel
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.