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

Tib*_*ker 10 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)
Run Code Online (Sandbox Code Playgroud)

这是我的游戏模型:

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)
Run Code Online (Sandbox Code Playgroud)

我根据这个 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.
Run Code Online (Sandbox Code Playgroud)

就像警告所说,当使用此配置时,我会在某个时刻得到:

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))
Run Code Online (Sandbox Code Playgroud)

我不知道该怎么做,我尝试阅读文档并测试了许多其他配置,但没有任何效果。非常感谢所有帮助。谢谢!

Tib*_*ker 8

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

current_president_id = db.Column(db.Integer, db.ForeignKey('player.id', use_alter=True))
Run Code Online (Sandbox Code Playgroud)

这使得警告消失。但现在你仍然需要小心。因为 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()
Run Code Online (Sandbox Code Playgroud)

这将引发 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()
Run Code Online (Sandbox Code Playgroud)

编辑:

use_alter=True在关系中使用可以防止任何 CircularDependencyErrors。这样,当您在一次提交中添加带有玩家的游戏和关系时,该关系将在第二个“ALTER”语句中设置,以防止循环依赖。