SQLAlchemy: несколько ForeignKeyConstraint ссылаются на один и тот же столбец назначения - PullRequest
0 голосов
/ 07 января 2020

Я пытаюсь правильно определить отношения между несколькими таблицами, которые все используют составные ключи. Проблема, с которой я сталкиваюсь, заключается в том, что один столбец, используемый в этих ключах, является общим для всех таблиц.

Рассмотрим следующие таблицы и отношения, написанные с использованием sqlalchemy:

class Match(Base):
    __tablename__ = 'match'
    id = Column(String, primary_key=True, nullable=False)
    players = relationship('PlayerMatch', back_populates='match')
    region = Column(String, primary_key=True, nullable=False)

class Player(Base):
    __tablename__ = 'player'
    id = Column(String, primary_key=True, nullable=False)
    matches = relationship('PlayerMatch', back_populates='player')
    region = Column(String, primary_key=True, nullable=False)

class PlayerMatch(Base):
    __tablename__ = 'player_match'
    match = relationship('Match', back_populates='players')
    match_id = Column(String, primary_key=True, nullable=False)
    player = relationship('Player', back_populates='matches')
    player_id = Column(String, primary_key=True, nullable=False)
    region = Column(String, primary_key=True, nullable=False)

    __table_args__ = (
        ForeignKeyConstraint(['region', 'player_id'], ['player.region', 'player.id']),
        ForeignKeyConstraint(['region', 'match_id'], ['match.region', 'match.id']),
    )

Это явно конфликтно для sqlachemy, поскольку он не знает, как заполнить атрибут region для PlayerMatch. Выдается следующее предупреждение:

SAWarning: relationship 'PlayerMatch.match' will copy column match.region to column player_match.region, which conflicts with relationship(s): 'PlayerMatch.match' (copies player.region to player_match.region). Consider applying viewonly=True to read-only relationships, or provide a primaryjoin condition marking writable columns with the foreign() annotation.

Обратите внимание, что region гарантированно будет одинаковым как для матча, так и для игрока, участвующего в этом отношении. Как и раньше, он все еще работает, но выдает мне предыдущее предупреждение. Я потратил некоторое время, пытаясь определить условия соединения различных отношений, но не могу заставить его работать должным образом. Я был бы согласен с механизмом, который бы просто указывал, какой region (исходя из Match или Player) должен сохраняться в PlayerMatch.

Каков правильный способ достижения это?

Спасибо за вашу помощь.

1 Ответ

1 голос
/ 09 января 2020

Решение состоит в том, чтобы указать атрибут primaryjoin отношения PlayerMatch.player, чтобы он мог использовать оба значения Player.id и Player.region, но чтобы предотвратить сохранение region, полученного из Player, так как следует:

player = relationship(
        'Player',
        back_populates='matches',
        primaryjoin="and_(Player.id == foreign(PlayerMatch.player_id), "
                    "Player.region == PlayerMatch.region)"
    )
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...