【问题标题】:sqlalchemy foreignkey relation with parent classsqlalchemy 与父类的外键关系
【发布时间】:2018-03-03 00:25:29
【问题描述】:

我有以下数据库架构:

父表:

  1. id - 主键标识符。
  2. 类型 - 多态身份。
  3. 名称 - 字符串数据列。

子表 - 继承父表:

  1. id - 主键标识符。
  2. parent_id - Parent 的外键。
  3. 类别 - 字符串数据列。

总结一下,我有两张桌子。表 Child 继承自 Parent 并且也有一个外键。

UPD:我真的需要继承和外键。此示例只是重现问题的简短演示。

我使用 declarative_base 来声明架构:

# -*- coding: utf-8 -*-

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

Base = declarative_base()

class Parent(Base):
  __tablename__ = "Parent"
  id = Column(Integer, primary_key=True)
  type = Column(String(250))

  name = Column(String(250))

  __mapper_args__ = {
    'polymorphic_identity':'Parent',
    'polymorphic_on':type
  }

class Child(Parent):
  __tablename__ = 'Child'
  id = Column(Integer, ForeignKey('Parent.id'), primary_key=True)

  parent_id = Column(ForeignKey("Parent.id"), nullable=True)
  category = Column(String(250))

  __mapper_args__ = {
    'polymorphic_identity':'Child',
  }

engine = create_engine('postgresql+psycopg2://joe:joe@localhost/alch')

session = sessionmaker()
session.configure(bind=engine)
Base.metadata.create_all(engine)

但是当我运行代码时出现以下错误:

sqlalchemy.exc.AmbiguousForeignKeysError:无法确定“父”和“子”之间的连接;表之间存在多个外键约束关系。请明确指定此连接的“onclause”。

我尝试自己为 Parent 或 Child 分别设置关系属性,也为两者设置关系属性。尝试使用关系的primaryjoin 和foreign_keys 参数。但是错误是一样的。

我完全对这个错误感到困惑。 我需要帮助。

【问题讨论】:

  • 您不需要从Parent 继承,因为您确定您的fk 与Parent 并没有其他相关。将class Child(Parent): 更改为class Child(Base):
  • @ShawnMehan 我真的需要继承。这是一个演示数据库模式,用于重现错误。我的真实架构有 1000 多个具有复杂继承的类。
  • 你能创建一个父子都继承的基类吗?

标签: python database sqlalchemy foreign-keys hierarchy


【解决方案1】:

您是否尝试过删除子 ID 字段的外键?

id = Column(Integer, ForeignKey('Parent.id'), primary_key=True)
parent_id = Column(ForeignKey("Parent.id"), nullable=True)

你需要这样的东西:

id = Column(Integer, auto_increment=True, primary_key=True)
parent_id = Column(ForeignKey("Parent.id"), nullable=True)

【讨论】:

  • 那行得通。新对象的插入工作正常。当我创建架构时,sqlalchemy 警告我消息“SAWarning:在属性 'id' 下将列 Parent.id 与列 Child.id 隐式组合。请为这些同名列显式配置一个或多个属性”。
  • 啊,不。此方法不起作用,因为它混淆了 sqlalchemy 继承功能。 SQLAlchemy 开始在子表中使用“parent_id”(而不是“id”)与父表链接。但是我需要 Child.id 上的继承链接和 Child.parent_id 上的多对多
【解决方案2】:

我找到了解决方案here。

SQLAlchemy 在这种情况下需要提示:Child 的 __mapper_args__ 中的 inherit_condition 字段可以解决问题。

# -*- coding: utf-8 -*-

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

Base = declarative_base()

class Parent(Base):
  __tablename__ = "Parent"
  id = Column(Integer, primary_key=True)
  type = Column(String(250))

  name = Column(String(250))

  __mapper_args__ = {
    'polymorphic_identity':'Parent',
    'polymorphic_on':type
  }

class Child(Parent):
  __tablename__ = 'Child'
  id = Column(Integer, ForeignKey('Parent.id'), primary_key=True)

  parent_id = Column(ForeignKey("Parent.id"), nullable=True)
  category = Column(String(250))

  parent = relationship(Parent, foreign_keys=[parent_id])

  __mapper_args__ = {
    'polymorphic_identity':'Child',
    'inherit_condition': id == Parent.id, 
  }

engine = create_engine('postgresql+psycopg2://joe:joe@localhost/alch')

session = sessionmaker()
session.configure(bind=engine)
Base.metadata.create_all(engine)

【讨论】:

    猜你喜欢
    • 2017-05-24
    • 2013-09-19
    • 2012-02-29
    • 2018-11-14
    • 2011-02-25
    • 2018-05-30
    • 2016-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多