在 sqlalchemy 中两次反向引用相同的名称

H2O*_*H2O 4 python sqlalchemy

在我的数据库模式中有比赛和团队,一个团队有一个first_opponent和一个second_opponent. 现在,这些中的每一个都应该可以作为团队的反向引用。作为第一或第二对手没有真正的区别,因此反向引用应该具有相同的名称。但是,我不能简单地创建两个具有相同名称的反向引用。

这是我的表定义(以简化形式):

class Team(Base):
    __tablename__ = "teams"

    id = Column(Integer, primary_key=True)
    name = Column(String)

class Match(Base):
    __tablename__ = "matches"
    id = Column(Integer, primary_key=True)
    first_opponent_id = Column(Integer, ForeignKey("teams.id"))
    second_opponent_id = Column(Integer, ForeignKey("teams.id"))

    first_opponent = relationship("Team", backref=backref('matches'), foreign_keys=[first_opponent_id])
    second_opponent = relationship("Team", backref=backref('matches'), foreign_keys=[second_opponent_id])
Run Code Online (Sandbox Code Playgroud)

这是我得到的错误:

sqlalchemy.exc.ArgumentError: Error creating backref 'matches' on relationship 'Match.second_opponent': property of that name exists on mapper 'Mapper|Team|teams'
Run Code Online (Sandbox Code Playgroud)

解决此问题的最佳方法是什么,为什么存在此限制?

van*_*van 6

有一个限制,因为任何对象最多只能有一个同名的属性或方法。

但是,您可以执行以下操作:

  1. 使用两个不同的名字
  2. 创建第三个以在您需要检查所有匹配项时使用。在这里你可以使用简单的@property

编码:

class Team(Base):
    __tablename__ = "teams"

    id = Column(Integer, primary_key=True)
    name = Column(String)

    @property
    def matches(self):
        return self.matches_to + self.matches_from


class Match(Base):
    __tablename__ = "matches"
    id = Column(Integer, primary_key=True)
    first_opponent_id = Column(Integer, ForeignKey("teams.id"))
    second_opponent_id = Column(Integer, ForeignKey("teams.id"))

    first_opponent = relationship(
        "Team", backref=backref('matches_to'),
        foreign_keys=[first_opponent_id],
    )
    second_opponent = relationship(
        "Team", backref=backref('matches_from'),
        foreign_keys=[second_opponent_id],
    )
Run Code Online (Sandbox Code Playgroud)

以下测试代码现在应该可以工作:

t1, t2, t3 = Team(name='uno'), Team(name='due'), Team(name='tre')
m1 = Match(first_opponent=t1, second_opponent=t2)
m2 = Match(first_opponent=t1, second_opponent=t3)
m3 = Match(first_opponent=t2, second_opponent=t3)
assert 2 == len(t1.matches)
assert 2 == len(t2.matches)
assert 2 == len(t3.matches)
session.add_all([t1, t2, t3])
session.commit()

assert 2 == len(t1.matches)
Run Code Online (Sandbox Code Playgroud)