繁体   English   中英

如何使用 SQLAlchemy 设置具有关联对象的邻接列表?

[英]How do I set up a adjacency list with an association object with SQLAlchemy?

我正在尝试创建一个数据库模型,您可以在其中拥有一堆产品,这些产品可能是其他产品的一部分,也包含其他产品。 我已经想出了如何做到这一点:

product_to_product = Table(
    "product_to_product",
    Base.metadata,
    Column("id", Integer, primary_key=True),
    Column("parent_id", Integer, ForeignKey("products.id")),
    Column("child_id", Integer, ForeignKey("products.id")),
)


class Product(Base):
    __tablename__ = "products"

    id = Column(Integer, primary_key=True)

    parents = relationship(
        "Product",
        secondary=product_to_product,
        primaryjoin=id == product_to_product.c.parent_id,
        secondaryjoin=id == product_to_product.c.child_id,
        backref="children",
    )

这让我可以添加这样的产品:

root = Product()

parent1 = Product()
parent2 = Product()

child1 = Product()
child2 = Product()
child3 = Product()

root.children = [parent1, parent2]
parent1.children = [child1, child2, child3]
parent2.children = [child1, child2]

然后我可以获取所有产品,并且父母/孩子之间的链接完全按照我的意愿工作。

现在我想改用关联对象来管理链接,因为我想要额外的数据。 我试过这样设置:

class ParentReference(Base):
    __tablename__ = "parent_references"

    id = Column(Integer, primary_key=True)
    parent_id = Column(Integer, ForeignKey("products.id"))
    child_id = Column(Integer, ForeignKey("products.id"))
    additional_data = Column(String)


class Product(Base):
    __tablename__ = "products"

    id = Column(Integer, primary_key=True)

    parents = relationship(
        "Product",
        secondary=ParentReference,
        primaryjoin=id == ParentReference.child_id,
        secondaryjoin=id == ParentReference.parent_id,
        backref=backref("children"),
    )

如果通过多对多关系链接在一起的对象是两个不同的对象(如UserCommunity ),我发现了很多例子,但从来没有在这种情况下它是同一个对象。 我的尝试是从不同的例子拼凑起来的,但它不像以前那样与脚本一起工作。 我还看到过使用association_proxy函数和其他几种方法的示例,但我无法使其正常工作。

我的目标是能够像以前一样添加产品、链接它们并导航它们,而且还能够从Product访问ParentReference对象,以便我可以获取关于它的附加数据。 有人可以帮我解决这个问题吗?

经过更多的反复试验,我想出了如何做到这一点。 这是我的解决方案:

class ParentReference(Base):
    __tablename__ = "parent_references"

    parent_id = Column(Integer, ForeignKey("products.id"), primary_key=True)
    child_id = Column(Integer, ForeignKey("products.id"), primary_key=True)
    extra_data = Column(String)

    parent = relationship(
        "Product",
        primaryjoin=lambda: ParentReference.child_id == Product.id,
        backref="child_references"
    )
    child = relationship(
        "Product",
        primaryjoin=lambda: ParentReference.parent_id == Product.id,
        backref="parent_references"
    )


class Product(Base):
    __tablename__ = "products"

    id = Column(Integer, primary_key=True)

    parents = relationship(
        "Product",
        secondary="parent_references",
        primaryjoin=lambda: Product.id == ParentReference.parent_id,
        secondaryjoin=lambda: Product.id == ParentReference.child_id,
        backref="children"
    )

这像这样工作:

root = Product()
parent1 = Product()
parent2 = Product()
child1 = Product()
child2 = Product()
child3 = Product()

parent1.parent_references = [
    ParentReference(parent=root, child=parent1, extra_data="Hello World!")
]
root.children.append(parent2)
parent1.children = [child1, child2, child3]
parent2.children = [child1, child2]

它允许我访问父母/孩子,以及参考对象和其中的额外数据。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM