SQLAlchemy多对多关联:如何获取帖子投票统计数据?
多对多投票关联表的统计数据获取方案
嘿,我来帮你搞定这个多对多关联的统计问题~先给你提个小建议:你当前UserVotesPost里的child = relationship("Post")其实有点冗余,咱们先把模型的关联关系调整得更清晰些,这样后续查数据会更顺手:
from sqlalchemy import Column, Integer, Boolean, DateTime, ForeignKey from sqlalchemy.ext.declarative import declarative_base from sqlalchemy.orm import relationship, UserMixin Base = declarative_base() class UserVotesPost(Base): __tablename__ = 'uservotesposts' user_id = Column(Integer, ForeignKey('users.id'), primary_key=True) post_id = Column(Integer, ForeignKey('posts.id'), primary_key=True) likes_post = Column(Boolean, nullable=False) date_added = Column(DateTime, nullable=False) # 双向关联User和Post,方便双向查询 user = relationship("User", back_populates="votes") post = relationship("Post", back_populates="votes") class User(UserMixin, Base): __tablename__ = 'users' id = Column(Integer, primary_key=True) # 其他用户字段(如username、email等)... votes = relationship("UserVotesPost", back_populates="user") class Post(Base): __tablename__ = 'posts' id = Column(Integer, primary_key=True) # 其他帖子字段(如title、content等)... votes = relationship("UserVotesPost", back_populates="post")
调整完关联后,咱们来看几种常用的统计场景:
1. 统计单篇帖子的点赞/踩数
如果想知道某篇帖子的具体投票数据,直接用聚合查询即可:
from sqlalchemy import func # 目标帖子ID target_post_id = 1 # 统计点赞数 like_count = session.query(func.count(UserVotesPost.user_id)).filter( UserVotesPost.post_id == target_post_id, UserVotesPost.likes_post == True ).scalar() # 统计踩数 dislike_count = session.query(func.count(UserVotesPost.user_id)).filter( UserVotesPost.post_id == target_post_id, UserVotesPost.likes_post == False ).scalar() print(f"帖子{target_post_id}:点赞{like_count}次,踩{dislike_count}次")
2. 查看用户对某篇帖子的投票状态
想确认某个用户是否给某篇帖子投过票,以及投票类型:
target_user_id = 1 target_post_id = 1 vote_status = session.query(UserVotesPost.likes_post).filter( UserVotesPost.user_id == target_user_id, UserVotesPost.post_id == target_post_id ).scalar() if vote_status is None: print(f"用户{target_user_id}还没给帖子{target_post_id}投票") else: vote_type = "点赞" if vote_status else "踩" print(f"用户{target_user_id}给帖子{target_post_id}投了{vote_type}")
3. 批量统计所有帖子的点赞/踩数
如果要一次性获取全量帖子的投票数据,用group_by分组统计,还能关联Post表拿到帖子基础信息:
post_stats = session.query( Post.id, Post.title, # 假设Post表有title字段 func.count(func.filter(UserVotesPost.likes_post == True)).label("like_count"), func.count(func.filter(UserVotesPost.likes_post == False)).label("dislike_count") ).outerjoin(UserVotesPost, Post.id == UserVotesPost.post_id) \ .group_by(Post.id) \ .all() # 遍历输出结果 for stat in post_stats: print(f"帖子ID: {stat.id} | 标题: {stat.title} | 点赞: {stat.like_count} | 踩: {stat.dislike_count}")
这里用outerjoin是为了确保无投票记录的帖子也能被统计到(点赞/踩数为0)。
4. 查看某个用户的所有投票记录
想梳理某个用户的投票历史,包括投票的帖子、时间和类型:
target_user_id = 1 user_votes = session.query( Post.id, Post.title, UserVotesPost.likes_post, UserVotesPost.date_added ).join(UserVotesPost, User.id == UserVotesPost.user_id) \ .join(Post, UserVotesPost.post_id == Post.id) \ .filter(User.id == target_user_id) \ .order_by(UserVotesPost.date_added.desc()) \ .all() for vote in user_votes: vote_type = "点赞" if vote.likes_post else "踩" print(f"帖子: {vote.title} | 投票类型: {vote_type} | 投票时间: {vote.date_added}")
额外优化建议
如果你的网站投票量较大,频繁做聚合查询可能影响性能。可以考虑在Post表中添加like_count和dislike_count两个缓存字段,每次用户投票(新增/修改投票记录)时同步更新这两个字段的值。这样后续统计时直接读取字段即可,不用再做聚合,性能会提升很多。
内容的提问来源于stack exchange,提问作者Roman
相关产品推荐
相关产品推荐

