我正在尝试更新一个简单的三层关系表集。
他们是
该模型的 SQLAlchemy 代码如下所示
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
name = Column(String)
children = relationship("Child", back_populates="parents")
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
name = Column(String)
parent_id = Column(Integer, ForeignKey('parent.id'))
parents = relationship("Parent", back_populates="children")
grandchildren = relationship("GrandChild",
back_populates="grandparent",
)
class GrandChild(Base):
__tablename__ = 'grandchild'
id = Column(Integer, primary_key=True)
name = Column(String)
parent_id = Column(Integer, ForeignKey('parent.id'))
child_id = Column(Integer, ForeignKey('child.id'))
grandparent = relationship("Child", back_populates="grandchildren")
Run Code Online (Sandbox Code Playgroud)
插入代码看起来像这样......
p3 = Parent(name="P3")
c5 = Child(name="C5")
c6 = Child(name="C6")
gc1 = GrandChild(name="gc1")
gc2 = GrandChild(name="gc2")
gc3 = GrandChild(name="gc3")
gc4 = GrandChild(name="gc4")
p3.children = [c5, c6]
c5.grandchildren = [gc1]
c6.grandchildren = [gc2, gc3, gc4]
session.add_all([p2, p3])
session.commit()
Run Code Online (Sandbox Code Playgroud)
记录已添加 - 并且父/子已正确链接 - 但孙子缺少父外键。
我一直在努力寻找正确的机制来添加这个 - 谁能指出我正确的方向?
您不会在孙子和父母之间建立关系。
孙子和父母之间的关系并不隐含在您的数据模型中;而是隐含在您的数据模型中。孩子的父母不会自动成为孩子所有孙子的父母。
您必须明确定义该关系,即将其添加到GrandChild:
class GrandChild(Base):
[...]
parent = relationship("Parent")
Run Code Online (Sandbox Code Playgroud)
然后在实例上创建关系:
gc1.parent = p3
gc2.parent = p3
gc3.parent = p3
gc4.parent = p3
Run Code Online (Sandbox Code Playgroud)
这将相应地添加记录:
sqlalchemy.engine.base.Engine INSERT INTO grandchild (name, parent_id, child_id) VALUES (?, ?, ?)
sqlalchemy.engine.base.Engine ('gc1', 1, 1)
[...]
Run Code Online (Sandbox Code Playgroud)
但是,由于数据模型中的父子关系并不意味着任何孙子-父子关系,因此您可以创建一个没有子项但有孙子项的父项。
sink = Parent(name="SINK")
gc1.parent = sink
print("Name: {}, Parent: {}, Parent.children: {}, Child.parent: {}"
.format(gc1.name, gc1.parent.name, gc1.parent.children, gc1.grandparent.parents.name))
# Name: gc1, Parent: SINK, Parent.children: [], Child.parent: P3
Run Code Online (Sandbox Code Playgroud)
根据我对三层关系的理解,我想不出一个用例。这样就会找到一个应用程序。
如果您希望通过子项在父项和孙项之间建立隐式且一致的关系,请删除父项和孙项之间的直接关系:
class Parent(Base):
__tablename__ = 'parent'
id = Column(Integer, primary_key=True)
name = Column(String)
children = relationship("Child", back_populates="parent")
def __repr__(self):
return "{}(name={})".format(self.__class__.__name__, self.name)
class Child(Base):
__tablename__ = 'child'
id = Column(Integer, primary_key=True)
name = Column(String)
parent_id = Column(Integer, ForeignKey('parent.id'))
parent = relationship("Parent", back_populates="children")
children = relationship("GrandChild", back_populates="parent")
# same __repr__()
class GrandChild(Base):
__tablename__ = 'grandchild'
id = Column(Integer, primary_key=True)
name = Column(String)
child_id = Column(Integer, ForeignKey('child.id'))
parent = relationship("Child", back_populates="children")
# same __repr__()
p3 = Parent(name="P3")
c5 = Child(name="C5")
gc1 = GrandChild(name="gc1")
p3.children = [c5]
c5.children = [gc1]
Run Code Online (Sandbox Code Playgroud)
您可以通过以下方式联系孙子的祖父母:
print(gc1.parent.parent)
# Parent(name=P3)
Run Code Online (Sandbox Code Playgroud)
不过,由于层次结构中存在两个一对多关系,另一种方法就有点乏味了:
for child in p3.children:
for gc in child.children:
print(p3, child, gc)
# Parent(name=P3) Child(name=C5) GrandChild(name=gc1)
Run Code Online (Sandbox Code Playgroud)