You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 02:33:06