【问题标题】:How do I set up a adjacency list with an association object with SQLAlchemy?如何使用 SQLAlchemy 设置具有关联对象的邻接列表?
【发布时间】:2021-01-20 14:45:26
【问题描述】:

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

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 对象,这样我就可以获取关于它的附加数据。有人可以帮我解决这个问题吗?

【问题讨论】:

    标签: python orm sqlalchemy adjacency-list


    【解决方案1】:

    经过更多的尝试和错误,我想出了如何做到这一点。这是我的解决方案:

    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]
    

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

    【讨论】:

      猜你喜欢
      • 2021-01-18
      • 2019-10-16
      • 1970-01-01
      • 1970-01-01
      • 2021-10-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-02
      相关资源
      最近更新 更多