如何在flask-sqlalchemy中实现三方多对多关系
在flask-sqlalchemy中,如何正确设计一个三方多对多的关系?
假设我有用户、团队和角色。用户被分配到团队中。当用户被分配到一个团队时,他们在这个团队中也会被分配一个角色。
from myapp import db
class User(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), unique=True)
def __init__(self, name):
self.name = name
def __repr__(self):
return "<User(%s)>" % self.name
class Team(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), unique=True)
def __init__(self, name):
self.name = name
def __repr__(self):
return "<Team(%s)>" % self.name
class Role(db.Model):
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(128), unique=True)
def __init__(self, name):
self.name = name
def __repr__(self):
return "<Role(%s)>" % self.name
我尝试了几种方法来设计一个代理表,但都没有成功。我觉得我可能误解了文档,所以不想把我之前失败的方法告诉你,以免让你更困惑。
我想留下一个问题:在flask-sqlalchemy中,如何正确设计一个三方多对多的关系?
2 个回答
-3
伙计们。解决两个多对多关系问题的官方方法是使用一个辅助表。
Helper_table = db.Table('Helper_table',
db.Column('id_a', db.Integer,
db.ForeignKey('a.id')),
db.Column('id_b', db.Integer,
db.ForeignKey('b.id'))
)
class A(db.Model): # A ORM
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
bs = db.relationship(
'B', secondary=Helper_table, lazy='dynamic')
def __repr__(self):
return '<A {}>'.format(self.username)
class B(db.Model): # B ORM
id = db.Column(db.Integer, primary_key=True)
username = db.Column(db.String(64), index=True, unique=True)
as = db.relationship(
'A', secondary=Helper_table, lazy='dynamic')
def __repr__(self):
return '<B {}>'.format(self.username)
不过,这个方法只能解决两个多对多的问题!!!它会自动处理这些关系。
a1 = A(username="a1_"+str(uuid.uuid4()))
b1 = B(username="b1_"+str(uuid.uuid4()))
a1.bs.append(b1)
db.session.add(a1)
db.session.commit()
就像上面的代码所示,它会自动把 b1
加入数据库,还有 b1.as
。
但是当我尝试在三个多对多关系的情况下使用这个方法时,一切都乱套了。
这是我问的问题:在flask-sqlalchemy中处理多对多对多关系的多个辅助表
总的来说,我觉得这应该是这个库的一个功能。应该有一种优雅的方法来处理这个问题。
20
经过大量的研究和探索,我终于找到了答案。因为我发现很多人也在为这个问题苦恼,却找不到一个完整清晰的解答,所以我决定把这个分享出来,方便以后遇到这个问题的人。
如果你也在问这个问题,可能你并不是真的在寻找一个三方多对多的关系。我原以为我在找这个,但其实并不是。
总结一下:我有用户、团队和角色。如果一个用户加入了一个团队,他在这个团队里也会被分配一个角色。
我回到白板上,画出了我真正想要的东西:
+---------+---------+---------+
| user_id | team_id | role_id |
+---------+---------+---------+
| 1 | 1 | 1 |
+---------+---------+---------+
然后我开始明白,其实我并不需要一个三方多对多的关系,而是需要一个三方一对多的关系,并且是从一个第四个模型出发。
class Membership(db.Model):
user_id = db.Column(db.Integer, db.ForeignKey('user.id'), primary_key=True)
team_id = db.Column(db.Integer, db.ForeignKey('team.id'), primary_key=True)
role_id = db.Column(db.Integer, db.ForeignKey('role.id'), primary_key=True)
db.UniqueConstraint('user_id', 'team_id', 'role_id')
db.relationship('User', uselist=False, backref='memberships', lazy='dynamic')
db.relationship('Team', uselist=False, backref='memberships', lazy='dynamic')
db.relationship('Role', uselist=False, backref='memberships', lazy='dynamic')
def __init__(self, user, team, role):
self.user_id = user.id
self.team_id = team.id
self.role_id = role.id
def __repr__(self):
return "<Membership(%s)>"
案例42:这正是我一直在寻找的答案——我只是问错了问题。