SQLAlchemy 关系:与两个 ForeignKey 列中的任一个匹配的对象列表

Posted

技术标签:

【中文标题】SQLAlchemy 关系:与两个 ForeignKey 列中的任一个匹配的对象列表【英文标题】:SQLAlchemy relationship: list of objects matching either of two ForeignKey columns 【发布时间】:2021-11-29 01:00:29 【问题描述】:

我的数据库中有两张表,一张用于比赛,一张用于团队。比赛的列中存储了参赛球队的 ID。

class Match(Base):
    id_ = Column(UUID(as_uuid=True, primary_key=True)
    team1_id = Column(UUID(as_uuid=True), ForeignKey('teams.id')
    team2_id = Column(UUID(as_uuid=True), ForeignKey('teams.id')

class Team(Base):
    id_ = Column(UUID(as_uuid=True, primary_key=True)

我想在两个表之间创建这样的关系:

Match.teams 返回两个 Team 对象的列表,其中包含 id 与 team1_idteam2_id 匹配的团队 Team.matches 返回Match 对象列表,其中包含team1_idteam2_id 列中存在该团队ID 的所有匹配项

从 SQL 的角度来看,我不需要另一个表 - 所有关系信息都存在于上述表中。但是,SQLAlchemy 是否需要关联表才能工作?

尝试 1

class Match(Base):
    ...
    teams = relationship('Team', back_populates='matches', lazy='selectin',
                         foreign_keys=[team1_id, team2_id])

class Team(Base):
    ...
    matches = relationship('Match', back_populates='teams', lazy='selectin')

导致以下错误:

sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Match.teams - there are multiple foreign key paths 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.

这让我感到困惑,因为我认为那是我正在做的事情!我做错了什么?

尝试 2

class Match(Base):
    ...
    teams = relationship('Team',
                         back_populates='matches',
                         lazy='selectin',
                         primaryjoin=('or_(Team.id==Match.team1_id,'
                                          'Team.id==Match.team2_id)'))


class Team(Base):
    ...
    matches = relationship('Match', back_populates='teams', lazy='selectin')

这导致 Match.teams 返回第一个团队的单个值,其 id 与 team1_idteam2_id 匹配。

我想做的事可能吗?应该怎么做?是否可以不在数据库中创建另一个表?

【问题讨论】:

【参考方案1】:

您可以使用属性来执行此操作,这可能更容易阅读:

class Match(Base):
    ...
    @property
    def teams(self) -> Tuple[Team, Team]:
        return session.get(Team, self.team1_id), session.get(Team, self.team2_id)

您可以像使用任何其他属性一样使用它:match.teams 是 Team 对象的元组。

【讨论】:

鉴于这是一个选项,为什么 sqlalchemy relationships 存在?感知到的优势是什么? 请注意,这不适用于异步数据库 relationship 在通常情况下简单易行:该字段与该字段相关。它为您提供英文描述,SQLAlchemy 为您进行查询。问题中的示例绝对是一个不寻常的案例,所以我并不惊讶它不支持开箱即用。

以上是关于SQLAlchemy 关系:与两个 ForeignKey 列中的任一个匹配的对象列表的主要内容,如果未能解决你的问题,请参考以下文章

如何访问与异步 sqlalchemy 的关系?

如何建立允许不同类型用户在 SqlAlchemy 中注册的数据库关系

SQLAlchemy如何反映多对多关系

与 SQLAlchemy 的分支关系

外键(foreign key)的使用及其优缺点

mysql foreign key(外键) 说明与实例