您使用association object 的多对多关系。
我认为模型还可以,但我对它们进行了一些重组。
class Vote(db.Model):
__tablename__ = 'votes'
id = db.Column(db.Integer, primary_key=True)
# Foreign Keys
plan_id = db.Column(db.Integer, db.ForeignKey('plans.id'))
post_id = db.Column(db.Integer, db.ForeignKey('posts.id'))
user_id = db.Column(db.Integer, db.ForeignKey('users.id'))
# Relationships
# If a user, post or plan is deleted, referencing votes are also removed.
# The associated plans and posts are loaded with the vote using a JOIN statement.
plan = db.relationship('Plan',
backref=db.backref('votes', cascade='all, delete-orphan'),
lazy='joined')
post = db.relationship('Post',
backref=db.backref('votes', cascade='all, delete-orphan'),
lazy='joined')
user = db.relationship('User',
backref=db.backref('votes', cascade='all, delete-orphan'))
def __repr__(self):
return f'Vote(plan_id={self.plan_id}, post_id={self.post_id}, user_id={self.user_id})'
class Plan(db.Model):
__tablename__ = 'plans'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(255), index=True, nullable=False)
def __repr__(self):
return f'Plan(name={self.name})'
class Post(db.Model):
__tablename__ = 'posts'
id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String(255), index=True, nullable=False)
def __repr__(self):
return f'Post(title={self.title})'
class User(db.Model):
__tablename__ = 'users'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), index=True, nullable=False)
# All plans and posts that have been voted for can be reached via jointable.
# CAUTION, objects can be added to the lists, but because of the viewonly flag
# they are not transferred to the database during a commit.
# An inconsistent state is therefore possible.
#
# _voted_plans = db.relationship(
# 'Plan',
# secondary='votes',
# backref=db.backref('users_voted', viewonly=True),
# viewonly=True
# )
#
# _voted_posts = db.relationship(
# 'Post',
# secondary='votes',
# backref=db.backref('users_voted', viewonly=True),
# viewonly=True
# )
def __repr__(self):
return f'User(name={self.name})'
一方面,您可以使用 ORM 方法使用虚拟关系来
列出所有相关的模型。在这种情况下,您的表投票充当可连接的
并且可以直接查询 Post 和 Plan 类的关联对象
通过关系。
plan_post_pairs = [(vote.plan, vote.post) for vote in Vote.query.filter_by(user_id=user_id).all()]
作为替代方案,您也可以编写自己的请求。
作为一个例子,我会给你一个 SQL SELECT 语句和一个 JOIN 语句。
我还要求提供投票标识符以列出用户对相同计划-帖子组合的重复投票。
# SELECT stmt
items = db.session.query( # SELECT ... FROM ...
Vote.id, Plan, Post
).filter( # WHERE ...
Vote.plan_id == Plan.id, # ... AND
Vote.post_id == Post.id, # ... AND
Vote.user_id == user_id # ...
).all()
# JOIN stmt
items = db.session.query(Vote.id, Plan, Post)\ # SELECT ...
.select_from(Vote)\ # FROM ...
.outerjoin(Plan, Post)\ # LEFT OUTER JOIN ... ON ...
.filter(Vote.user_id == user_id)\ # WHERE ...
.all()
以下示例更高级一些,将来可能会对您有所帮助。请求用户的所有计划-发布组合,包括该用户对相应组合的投票数。
subquery = db.session\
.query(Vote.plan_id, Vote.post_id, db.func.count('*').label('count'))\
.group_by(Vote.plan_id, Vote.post_id)\
.filter(Vote.user_id == user_id)\
.subquery()
items = db.session\
.query(Plan, Post, subquery.c.count)\
.select_from(subquery)\
.outerjoin(Plan, subquery.c.plan_id == Plan.id)\
.outerjoin(Post, subquery.c.post_id == Post.id)\
.all()