【问题标题】:SQLAlchemy: AmbiguousForeignKeysError double reference to parentSQLAlchemy:AmbiguousForeignKeysError 对父级的双重引用
【发布时间】:2023-04-09 09:04:01
【问题描述】:

对于可以具有角色子组的组,我有以下简化代码:

from sqlalchemy import (
    CheckConstraint,
    Column,
    ForeignKey,
    PrimaryKeyConstraint,
    String,
    create_engine,
)
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy.orm import sessionmaker, relationship

Base = declarative_base()


class Group(Base):
    __tablename__ = 'groups'
    name = Column(String, primary_key=True)
    group_roles = relationship('GroupRole', back_populates='group')


class GroupRole(Base):
    __tablename__ = 'group_roles'
    name = Column(String, ForeignKey(Group.name))
    group_name = Column(String, ForeignKey(Group.name))
    role = Column(String, nullable=False)
    __table_args__ = (
        CheckConstraint('name != group_name'),
        PrimaryKeyConstraint('name', 'group_name'),
    )
    group = relationship(Group,
                         foreign_keys=[name],
                         back_populates='group_roles')


engine = create_engine('sqlite:///:memory:')
Base.metadata.create_all(engine)
session = sessionmaker(bind=engine)()
session.add(Group(name='test'))

当我运行它时,我得到sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Group.group_roles - there are multiple foreign key path s linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.

我还尝试在GroupRole 表下方添加以下内容,以代替Group 中已经定义的相应行:

Group.group_roles = relationship('GroupRole', foreign_keys=[Column(String, ForeignKey(GroupRole.name))], back_populates='group')

但我遇到了同样的错误,而且看起来其他人不必这样做。我究竟做错了什么?如何让我的GroupRole 表引用我的Group 表?我正在使用 SQLAlchemy 1.3 和 python 3.7。

【问题讨论】:

  • 你为什么认为你首先需要这个“对父级的双重引用”?在GroupRole 中,您将namegroup_name 显式定义为相同的外键,并且您还将group 定义为关系。这实际上看起来更像是“对我的三重引用”。也许尝试只使用一个。
  • 所以这大大简化了,我还在实际代码中的组中获得了用户角色:在一天结束时,我希望每个组都有一个 user_roles 属性,该属性链接到用户角色和另一个链接到(子)group_roles。 IE。一个组由其他组和用户组成,每个组和用户都有自己的角色
  • 也许这是少有的例子之一,不太简化的例子是有意义的,我想说在GroupRole.group 关系上使用简单的backref,但我忍不住感觉我从这张图片中遗漏了一些东西,双外键业务与检查约束配对。无论如何,我的直觉是,这更多是数据模型本身的问题。
  • 例如,在下面查看我的答案。我仍然不确定Group.nameGroupRole.name 的外键,也许更详细的例子可以解释。

标签: python sqlalchemy foreign-keys


【解决方案1】:

您可以使代码在GroupRole.group 关系上仅与backref 一起工作,例如:

class Group(Base):
    __tablename__ = 'groups'
    name = Column(String, primary_key=True)

class GroupRole(Base):
    __tablename__ = 'group_roles'
    name = Column(String, ForeignKey(Group.name))
    group_name = Column(String, ForeignKey(Group.name))
    role = Column(String, nullable=False)
    __table_args__ = (
        CheckConstraint('name != group_name'),
        PrimaryKeyConstraint('name', 'group_name'),
    )
    group = relationship(Group,
                         foreign_keys=[name],
                         backref='group_roles')

虽然不确定这是预期的,但可以正常工作:

g = Group(name='test', group_roles=[
    GroupRole(group_name='testrole', name='test', role='testrole'),
    GroupRole(group_name='testrole2', name='test', role='testrole2')
])
session.add(g)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-04
    • 2013-03-29
    • 2012-12-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多