我什么时候需要使用sqlalchemy back_populates?

Liq*_*Lau 60 python sqlalchemy

当我按照本指南尝试SQLAlchemy Relation Example时:基本关系模式

我有这个代码

#!/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)
Run Code Online (Sandbox Code Playgroud)

它运作良好,但在指南中,它说模型应该是:

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")**
Run Code Online (Sandbox Code Playgroud)

为什么我不需要back_populatesbackref在我的例子中?我什么时候应该使用其中一种?

Bre*_*bel 127

如果您使用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'))
Run Code Online (Sandbox Code Playgroud)

如果您没有使用backref,并且relationship单独定义,那么如果您不使用back_populates,sqlalchemy将不知道连接关系,因此修改一个也会修改另一个.

因此,在您的示例中,您已经relationship单独定义了s,但没有提供back_populates参数,修改一个字段不会自动更新事务中的另一个字段.

>>> parent = Parent()
>>> child = Child()
>>> child.parent = parent
>>> print parent.children
[]
Run Code Online (Sandbox Code Playgroud)

看看它是如何不自动填写的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")
Run Code Online (Sandbox Code Playgroud)

所以现在我们得到了

>>> parent = Parent()
>>> child = Child()
>>> child.parent = parent
>>> print parent.children
[Child(...)]
Run Code Online (Sandbox Code Playgroud)

Sqlalchemy知道这两个字段现在是相关的,并且会在另一个更新时更新每个字段.值得注意的是,使用backref也会这样做.back_populates如果你想在每个类上定义关系,那么使用是很好的,所以很容易看到所有的字段都只是看了一下模型类,而不必查看通过backref定义字段的其他类.

  • 关于`back_populates`和`backref`的注释:`backref`更简洁,因为您不需要在两个类上都声明该关系,但是实际上我发现不值得在线保存它。我认为`back_populates`更好,不仅因为在python文化中_“ Explicit优于隐式” _(Python的Zen),而且当您有许多模型时,快速浏览一下它的声明,您可以看到所有关系及其关系。名称,而不是遍历所有相关模型。另外,`back_populates`的一个不错的好处是,您可以在大多数IDE的两个方向上自动完成=) (10认同)
  • @LuizTauffer “parent_id”是存储父子关系的实际外键字段。有必要。辅助表用于定义多对多关系(例如,如果一个子项可以有多个父项)。上面的 fkey 示例是经典的一对多示例,其中每个 Child 有一个且只有一个 Parent,而一个 Parent 可以有多个 Children。 (2认同)
  • 所有很棒的答案都在这里。只是添加一些我没有看到提到的内容;随着项目的发展,我开始遇到循环依赖问题。因此,在仅一端需要实体的情况下使用“backref”有助于减少遇到依赖关系的机会。 (2认同)