SQLAlchemy |多个一对一和一对多关系

时间:2020-11-12 16:32:33

标签: python sqlalchemy

我有两种模型:游戏和玩家。我想列出游戏模型中的所有玩家,以及其他领域的玩家之一。这是一个Flask服务器和一个sqlite数据库。

这是我的播放器型号:

class Player(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    # other fields...
    
    game_id = db.Column(db.Integer, db.ForeignKey('game.id'))
    game = db.relationship('Game', back_populates='players', foreign_keys=game_id)

这是我的游戏模型:

class Game(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    # other fields...

    current_president_id = db.Column(db.Integer, db.ForeignKey('player.id'))
    current_president = db.relationship("Player", foreign_keys=current_president_id)

    # other one-to-one relationships to the Player Model, exactly like the first one...

    players = db.relationship('Player', back_populates='game', foreign_keys=Player.game_id)

我基于this Response制作了两个模型。但是我仍然收到同样的警告:

SAWarning: Cannot correctly sort tables; there are unresolvable cycles between tables "game, player", which is usually caused by mutually dependent foreign key constraints.  Foreign key constraints involving these tables will not be considered; this warning may raise an error in a future release.

就像警告说的那样,当使用这种配置时,我会在某个时候得到:

sqlalchemy.exc.CircularDependencyError: Circular dependency detected. (SaveUpdateState(<Game at 0x23009e00160>), SaveUpdateState(<Player at 0x23009e141c0>), ProcessState(ManyToOneDP(Game.current_president), <Game at 0x23009e00160>, delete=False), ProcessState(OneToManyDP(Game.players), <Game at 0x23009e00160>, delete=False))

我不知道该怎么办,我试图通读文档并测试了许多其他配置,但是没有任何效果。所有帮助,不胜感激。谢谢!

1 个答案:

答案 0 :(得分:0)

因此,我尝试更深入地学习SQLAlchemy,并找到了解决方案。首先,以一对一关系将use_alter标志设置为True:

current_president_id = db.Column(db.Integer, db.ForeignKey('player.id', use_alter=True))

这使警告消失。但是您现在仍然需要小心。由于Player模型具有引用Game.id的列,而Game模型具有引用Player.id的列,因此您无法在一次提交中声明关系:

g, p1, p2 = Game(), Player(), Player()
db.session.add_all([g, p1, p2])
db.session.commit()
g.players = [p1, p2]
g.current_president = p3
db.session.commit()

这将引发CircularDependencyError。但这不会:

g, p1, p2 = Game(), Player(), Player()
db.session.add_all([g, p1, p2])
db.session.commit()
g.players = [p1, p2]
db.session.commit()
g.current_president = p3
db.session.commit()