【问题标题】:Using SQLAlchemy with composite primary and foreign keys将 SQLAlchemy 与复合主键和外键一起使用
【发布时间】:2017-08-20 10:26:08
【问题描述】:

我正在尝试使用声明性 SQLAlchemy (v1.1.5) 在两个表之间创建关系,其中表具有复合主键和外键。

这本质上是两个表之间的经典一对多关系,其中 Resource 定义了父级,每个资源都有多个段,在 Resourcesegment 表中定义。不同之处在于我在两个表中都添加了一个 VersionID 列,因此我可以将数据库与数据的多个版本一起使用。这是简化的代码:

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

Base = declarative_base()

class Resource(Base):
    __tablename__ = 'resource'
    VersionID = Column(String, primary_key=True)
    ResourceID = Column(String, primary_key=True)
    ResourceProperty = Column(String)
    segments = relationship("Resourcesegment", back_populates="resource")

class Resourcesegment(Base):
    __tablename__ = 'resourcesegment'
    VersionID = Column(String, primary_key=True)
    ResourceID = Column(String, primary_key=True)
    Segment_Type = Column(String, primary_key=True)
    Segment_Number = Column(Integer, primary_key=True)
    Segment_Property = Column(String)
    resource = relationship("Resource", foreign_keys=[VersionID, ResourceID], back_populates="segments")

    __table_args__ = (ForeignKeyConstraint([VersionID, ResourceID], [Resource.VersionID, Resource.ResourceID]),)

我得到的错误信息是:

InvalidRequestError: Mapper 'Mapper|Resourcesegment|resourcesegment' 没有属性 'resource'

我为关系和外键尝试了许多不同的配置,但都没有成功。根据我在文档和各种 Stackoverflow 示例中的理解,这是我对应该做什么的最佳猜测。显然我错过了一些东西。

感谢任何帮助/建议/cmets!

【问题讨论】:

  • 我有一种感觉(这是一个遥远的记忆)“反向填充”用于在“远程”模型/表上自动创建“来自”关系。如果您在每个模型上显式创建“到”关系,则根本不需要在任何一个模型的关系上进行反向填充。
  • 你试过像documentation那样使用backref吗?这样,您在父表中声明子关系,因此您不应该收到该错误。缺点是您不会有 foreign_keys 参数,但由于这些列已经在 ForeignKeyConstraint 中,我认为这应该不是问题。
  • 能否包含错误的完整堆栈跟踪。

标签: python sqlalchemy foreign-keys relationship foreign-key-relationship


【解决方案1】:

假设您尝试将分段 PK 用作资源的 FK,请尝试在 PK 属性定义上定义 FK,例如大致如下:

class Resourcesegment(Base):
    __tablename__ = 'resourcesegment'
    VersionID = Column(String, ForeignKey(Resource.VersionID), primary_key=True)
    ResourceID = Column(String, ForeignKey(Resource.ResourceID), primary_key=True)
    Segment_Type = Column(String, primary_key=True)
    Segment_Number = Column(Integer, primary_key=True)
    Segment_Property = Column(String)
    resource = relationship("Resource", back_populates="segments")

【讨论】:

  • 复合外键必须指定为 ForeignKeyConstraint:**需要注意的是 ForeignKeyConstraint 是定义复合外键的唯一方法**。见:link
【解决方案2】:

所以我正在回答我自己的问题!事实证明,我上面发布的原始代码是正确的。我遇到的问题是由于我正在开发的实际模型中有一组更复杂的表。其他表格之一有问题,最终引发错误,看起来问题出在上述表格上。当我剥离所有内容时,由于创建了这个 SO 帖子,我的简化模型开始工作,并且能够将问题隔离到更大模型的另一部分。

一个警告:来自 SQLAlchemy 的错误消息可能会非常混乱,并且不一定能够查明实际问题,而无需进行一些额外的调试工作。

【讨论】:

    猜你喜欢
    • 2023-03-08
    • 1970-01-01
    • 1970-01-01
    • 2012-01-27
    • 1970-01-01
    • 2016-06-16
    • 2017-01-30
    • 2017-08-06
    • 2018-04-07
    相关资源
    最近更新 更多