我想制作一个游戏桌,每个游戏应该指向两个玩家或用户。
这是我现在的代码。我正在使用SQLAlchemy
UserGame = db.Table('UserGame',
db.Column('game_id',db.Integer,db.ForeignKey('game.id')),
db.Column('user_id',db.Integer,db.ForeignKey('user.id')),
)
class User(db.Model):
__tablename__ = 'User'
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(80), unique=True)
email = db.Column(db.String(120), unique=True)
games = db.relationship('Game', secondary=UserGame, backref='players')
def __init__(self, username, email):
self.username = username
self.email = email
def __repr__(self):
return '<User %r>' % self.username
class Game(db.Model):
__tablename__ = 'Game'
id = db.Column(db.Integer, primary_key=True)
player1 = db.Column(db.Integer,db.ForeignKey('User.id')
player2 = db.Column(db.Integer,db.ForeignKey('User.id')
ended = db.Column(db.Boolean)
winner_username = db.Column(db.String(80),db.ForeignKey('User.username'))
但是,当我尝试创建用户时,出现以下错误:
sqlalchemy.exc.NoForeignKeysError: Could not determine join condition between parent/child tables on relationship User.games - there are no foreign keys linking these tables via secondary table 'UserGame'. Ensure that referencing columns are associated with a ForeignKey or ForeignKeyConstraint, or specify 'primaryjoin' and 'secondaryjoin' expressions.
有什么想法吗?
答案 0 :(得分:1)
一旦找到M:N关系,您即将使用所谓的关联类来描述这种关系。
在你的情况下,你有两个玩家之间的关系,协会的意思是“他们一起玩的游戏”。
最小关联类描述:
可能存在三元甚至更复杂的关联,但这些很少见。
在某些情况下,这就是Game的情况,我们可能会为该关联添加一些额外的数据(比如结果,谁是赢家等)。
描述同一类的两个实例之间的关联没有概念上的问题。
有三种方法可以在sqlalchemy中建模关联类
在sqlalchemy中,简单的M:N关系通常由所谓的辅助表建模。不幸的是,这不是这种情况,因为我们需要将附加信息附加到已知的关联。
这是您的理由。代码将随之而来。
有一些高级技术,使用association_proxy,可能会隐藏关联类实例,但我们不需要这个(实际上,我们希望在模型中看到游戏的概念)。
以下示例模型团队,可能会一起玩游戏。每场比赛都在主场进行,另一支球队被视为客人。我们会在每场比赛中记录一个分数。
此示例应易于根据您的方案进行修改。
from sqlalchemy import Column, Integer, String, ForeignKey
from sqlalchemy.orm import relationship
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class Team(Base):
__tablename__ = "team"
id = Column(Integer, primary_key=True)
name = Column(String(40))
def __init__(self, name):
self.name = name
def __repr__(self):
return "<Team: {self.name}>".format(self=self)
class Game(Base):
__tablename__ = "game"
host_id = Column(Integer, ForeignKey("team.id"), primary_key=True)
guest_id = Column(Integer, ForeignKey("team.id"), primary_key=True)
host_score = Column(Integer)
guest_score = Column(Integer)
def __init__(self, host, guest, host_score, guest_score):
self.host = host
self.guest = guest
self.host_score = host_score
self.guest_score = guest_score
host = relationship(Team, lazy="joined", foreign_keys="Game.host_id", backref="games_ashost")
guest = relationship(Team, lazy="joined", foreign_keys="Game.guest_id", backref="games_asguest")
def __repr__(self):
templ = "<Game: {self.host.name} vs {self.guest.name} score: {self.host_score}:{self.guest_score}>"
return templ.format(self=self)
除了设置课程Game
之外,为此课程玷污host
和guest
肉类信息非常重要。我们为此目的使用relationship
。
由于我们正在关联同一个类的两个实例,因此sqlalchemy很难找到要与host
链接的类属性以及与guest
链接的类属性。为此,relationship
必须使用foreign_keys
,它可能以数组或一串外键的形式使用。 (这对我来说是最难的部分,因为例子没有显示这样的例子)。
backref
中的{p> relationship
会向合作班级添加新属性,因此backref="games_ashost
会为每个Team
属性添加Team().games_ashost
。
导入所需内容
>>> from model import *
>>> from sqlalchemy import *
>>> from sqlalchemy.orm import Session
准备引擎和会话
>>> engine = create_engine("sqlite://")
>>> Base.metadata.create_all(engine)
>>> session = Session(engine)
创建团队alfa,beta,gama,delta
>>> alfa = Team("alfa")
>>> beta = Team("beta")
>>> gama = Team("gama")
>>> delta = Team("delta")
>>> alfa
<Team: alfa>
>>> beta
<Team: beta>
>>> gama
<Team: gama>
>>> delta
<Team: delta>
将它们存储在数据库中
>>> session.add_all([alfa, beta, gama, delta])
>>> session.commit()
实例化游戏(在Alfa和Beta以及Alfa和Gama之间)并将它们存储在数据库中
>>> game_ab = Game(alfa, beta, 0, 0)
>>> game_ab
<Game: alfa vs beta score: 0:0>
>>> game_ag = Game(alfa, gama, 0, 0)
>>> session.add_all([game_ab, game_ag])
>>> session.commit()
探索团队的可用属性
>>> alfa.games_ashost
[<Game: alfa vs beta score: 0:0>, <Game: alfa vs gama score: 0:0>]
>>> alfa.games_asguest
[]
>>> beta.games_ashost
[]
>>> beta.games_asguest
[<Game: alfa vs beta score: 0:0>]
>>> gama.games_ashost
[]
>>> gama.games_asguest
[<Game: alfa vs gama score: 0:0>]
>>> gama
<Team: gama>
探索游戏属性
>>> game_ab.host
<Team: alfa>
>>> game_ab.guest
<Team: beta>