sqlalchemy 模式:引用表没有匹配给定键的唯一约束

0 投票
1 回答
1480 浏览
提问于 2025-04-19 22:57

我正在尝试使用SQLAlchemy模型创建两个结构相同但目的不同的表,分别是Whitelist(白名单)和Blacklist(黑名单),这两个表都与一个Magazine(杂志)相关联(杂志的内容这里不展示)。它们都通过外键(fkey)连接到一个Campaign(活动)实例,比如说一个政治活动,而这个活动又有一个外键指向Politician(政治人物)模型(同样不展示)。

我想象中的WhitelistBlacklistCampaign之间是多对一的关系,因为可能会有多个白名单和黑名单对应同一个活动。但是在运行迁移时,我遇到了一个错误:sqlalchemy.exc.ProgrammingError: (ProgrammingError) there is no unique constraint matching given keys for referenced table "campaigns"。此外,CampaignPolitician之间也需要是多对一的关系。

有人能解释一下为什么会出现这个唯一约束错误吗?因为白名单和黑名单是在不同的表中。还有,我该如何让这个关系模型正常工作呢?

class Campaign(Base):
    __tablename__ = "campaigns"
    id = Column(Integer, primary_key=True, nullable=False)
    politician_id = Column(Integer, ForeignKey('politician.id'), nullable=False)
    description = Column(Text, nullable=True)


class Whitelist(Base):
    __tablename__ = "whitelist"
    id = Column(Integer, primary_key=True, nullable=False)
    campaign_id = Column(Integer, ForeignKey('campaign.id'), nullable=False)
    magazine_id = Column(Integer, ForeignKey('magazine.id'), nullable=False)


class Blacklist(Base):
    __tablename__ = "blacklist"
    id = Column(Integer, primary_key=True, nullable=False)
    campaign_id = Column(Integer, ForeignKey('campaign.id'), nullable=False)
    magazine_id = Column(Integer, ForeignKey('magazine.id'), nullable=False)

1 个回答

0

看起来这个关系确实不合法,因为从 Whitelist/BlacklistCampaign 是一种多对一的关系,而 Campaign 本身又是多对一地指向 Politician。所以我放弃了这种做法,现在的模型看起来是这样的:

class Campaign(Base):
    __tablename__ = "campaigns"
    id = Column(Integer, primary_key=True, nullable=False)
    politician_id = Column(Integer, ForeignKey('politician.id'), nullable=False)
    description = Column(Text, nullable=True)


class Listing(Base):
    __tablename__ = "listings"
    id = Column(Integer, primary_key=True, nullable=False)
    campaign_id = Column(Integer, ForeignKey('campaign.id'), nullable=False)
    magazine_id = Column(Integer, ForeignKey('magazine.id'), nullable=False)
    listing_type = Column(String, nullable=False)

最初的做法是为了更好地适应 Flask-Admin,但现在这种方式更高效,因为它减少了之前需要的额外查询和连接。如果你也在考虑用这种方式来配合 Flask-Admin,可以使用 inline_model() 来让界面看起来更整洁,更容易管理。

撰写回答