【问题标题】:SQLAlchemy Handling Multiple Paths In One RelationshipSQLAlchemy 在一个关系中处理多个路径
【发布时间】:2019-03-10 01:51:53
【问题描述】:

请注意:这个问题与我当前未解决的问题SQLAlchemy secondary join relationship on multiple foreign keys 相关但独立。

单个类中的SQLAlchemy documentation describes handling multiple join paths用于多个关系

from sqlalchemy import Integer, ForeignKey, String, Column
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import relationship

Base = declarative_base()

class Customer(Base):
    __tablename__ = 'customer'
    id = Column(Integer, primary_key=True)
    name = Column(String)

    billing_address_id = Column(Integer, ForeignKey("address.id"))
    shipping_address_id = Column(Integer, ForeignKey("address.id"))

    billing_address = relationship("Address")
    shipping_address = relationship("Address")

class Address(Base):
    __tablename__ = 'address'
    id = Column(Integer, primary_key=True)
    street = Column(String)
    city = Column(String)
    state = Column(String)
    zip = Column(String)

在同一部分中,文档显示了定义关系的三种不同方法:

  1. billing_address = relationship("Address", foreign_keys=[billing_address_id])

  2. billing_address = relationship("Address", foreign_keys="[Customer.billing_address_id]")

  3. billing_address = relationship("Address", foreign_keys="Customer.billing_address_id")

正如您在 (1) 和 (2) 中看到的那样,SQLAlchemy 允许您定义一个外键列表。事实上,文档明确指出:

在这个具体的例子中,列表在任何情况下都不是必需的,因为我们只需要一个列:billing_address = relationship("Address", foreign_keys="Customer.billing_address_id")

但我无法确定如何使用列表表示法在单个关系中指定多个外键

对于课程

class PostVersion(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    ...
    tag_1_id = db.Column(db.Integer, db.ForeignKey("tag.id"))
    tag_2_id = db.Column(db.Integer, db.ForeignKey("tag.id"))
    tag_3_id = db.Column(db.Integer, db.ForeignKey("tag.id"))
    tag_4_id = db.Column(db.Integer, db.ForeignKey("tag.id"))
    tag_5_id = db.Column(db.Integer, db.ForeignKey("tag.id"))

class Tag(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    tag = db.Column(db.String(127))

我已经尝试了以下所有方法:

  1. tags = db.relationship("Tag", foreign_keys=[tag_1_id, tag_2_id, tag_3_id, tag_4_id, tag_5_id]) 导致

sqlalchemy.exc.AmbiguousForeignKeysError:无法确定关系 AnnotationVersion.tags 上的父/子表之间的连接条件 - 有多个外键路径链接表。指定 'foreign_keys' 参数,提供应计为包含对父表的外键引用的列的列表。

  1. tags = db.relationship("Tag", foreign_keys="[tag_1_id, tag_2_id, tag_3_id, tag_4_id, tag_5_id]") 导致

sqlalchemy.exc.InvalidRequestError:初始化映射器 Mapper|AnnotationVersion|annotation_version 时,表达式 '[tag_1_id, tag_2_id, tag_3_id, tag_4_id, tag_5_id]' 未能找到名称(“名称 'tag_1_id' 未定义”)。如果这是一个类名,请考虑在定义了两个依赖类之后将此 relationship() 添加到该类中。

以及列表样式的许多其他变体,在内部和外部使用引号,使用表名和类名。

我实际上已经在这个问题的过程中解决了这个问题。由于似乎没有直接的文档,所以我会自己回答而不是删除这个问题。

【问题讨论】:

  • 似乎关联表也很合适,而不是重复的外键和复杂的连接。
  • @IljaEverilä ,我已经听过好几次了,但是关联表的问题(我假设您的意思是Tag-PostVersion 上的多对多)是我想要对每个 PostVersion 可以包含的标签数量进行硬性限制。我之所以得出这个架构,基本上是因为我认真思考了 stackoverflow 如何通过编辑实现标签和问题版本控制。如果标签发生变化,那就是编辑,并且很容易根据它存储新版本的问题。但是,如果它是一个多对多表,这似乎很困难。等待。我得了!我想我刚刚意识到了一个简单的方法!谢谢 Ilj

标签: python sqlalchemy


【解决方案1】:

关键是在主连接上定义关系并指定uselist参数。

tags = db.relationship("Tag", primaryjoin="or_(PostVersion.tag_1_id==Tag.id,"
     "PostVersion.tag_2_id==Tag.id, PostVersion.tag_3_id==Tag.id,"
     "PostVersion.tag_4_id==Tag.id, PostVersion.tag_5_id==Tag.id)",
     uselist=True)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2016-08-21
    • 2021-02-05
    • 2021-12-15
    • 1970-01-01
    • 2020-12-30
    • 2015-02-11
    • 2021-09-24
    • 1970-01-01
    相关资源
    最近更新 更多