Python 如何使用SQLAlchemy设置具有关联对象的邻接列表?
我正在尝试创建一个数据库模型,在这个模型中,您可以拥有一组产品,这些产品可以是其他产品的一部分,也可以包含其他产品。我已经想出了这样做的方法:Python 如何使用SQLAlchemy设置具有关联对象的邻接列表?,python,orm,sqlalchemy,adjacency-list,Python,Orm,Sqlalchemy,Adjacency List,我正在尝试创建一个数据库模型,在这个模型中,您可以拥有一组产品,这些产品可以是其他产品的一部分,也可以包含其他产品。我已经想出了这样做的方法: product_to_product = Table( "product_to_product", Base.metadata, Column("id", Integer, primary_key=True), Column("parent_id", Intege
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"),
)
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]
这让我可以添加如下产品:
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"),
)
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]
然后,我可以抓取所有的产品,父母/孩子之间的链接完全按照我的意愿工作
现在,我想转而使用关联对象来管理链接,因为我希望有更多的数据。我尝试过这样设置:
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"),
)
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]
我发现了许多这样做的例子,如果通过多对多关系链接在一起的对象是两个不同的对象(如User
和Community
),但在这种情况下,它是同一个对象。我的尝试是从不同的示例中拼凑而成的,但它与以前的脚本不兼容。我也看到过一些例子使用了association\u proxy
函数和其他几种方法,但我无法实现这一点
我的目标是能够像以前一样添加产品、链接产品和导航产品,还能够从
产品
访问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"
)
其工作原理如下:
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"),
)
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]
它允许我访问父/子对象,以及引用对象和其中的额外数据