Python SqlAlchemy外键向下传播3层

Python SqlAlchemy外键向下传播3层,python,sqlalchemy,Python,Sqlalchemy,我正在尝试更新一组简单的3层关系表 是的 母公司 孩子 孙子 模型的SQLAlchemy代码如下所示 class Parent(Base): __tablename__ = 'parent' id = Column(Integer, primary_key=True) name = Column(String) children = relationship("Child", back_populates="parents") class Child(Ba

我正在尝试更新一组简单的3层关系表

是的

  • 母公司
  • 孩子
  • 孙子
模型的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")
插入代码如下所示

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()
记录已添加-并且父/子项已正确链接-但子项缺少父项外键


我一直在努力寻找正确的机制来添加这一点-有人能给我指出正确的方向吗?

您没有创建孙子和父母之间的关系。
孙子和父母之间的关系在您的数据模型中并不隐含;孩子的父母不会自动成为孩子所有孙子孙女的父母

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
您必须明确定义该关系,即将其添加到
孙辈中

class GrandChild(Base):
    [...]
    parent = relationship("Parent")
然后在实例上创建关系:

gc1.parent = p3
gc2.parent = p3
gc3.parent = p3
gc4.parent = p3
这将相应地添加记录:

sqlalchemy.engine.base.Engine INSERT INTO grandchild (name, parent_id, child_id) VALUES (?, ?, ?)
sqlalchemy.engine.base.Engine ('gc1', 1, 1)
[...]
但是,由于数据模型中的父子关系并不意味着任何孙辈-父辈关系,因此可以创建一个没有子辈的、有孙辈的父辈

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
基于我对三层关系的理解,我想不出这样一个用例会有什么应用。
如果希望通过子对象在父对象和孙子对象之间建立隐式的一致关系,请删除父对象和孙子对象之间的直接关系:

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]
您可以通过以下方式访问孙辈的祖父母:

print(gc1.parent.parent)
# Parent(name=P3)
但是,另一种方法有点繁琐,因为层次结构中存在两种一对多的关系:

for child in p3.children:
    for gc in child.children:
        print(p3, child, gc)
# Parent(name=P3) Child(name=C5) GrandChild(name=gc1)

非常感谢您的想法和清晰的示例。我可以非常清楚地了解你的思维过程。我将重新审视我的用例,并相应地修改我的数据模型。