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

如何在Django ORM中实现LEFT JOIN查询获取帖子及指定用户对应评分

是否需要修改现有模型

无需修改现有模型即可实现需求,仅推荐做两处可选优化,提升数据一致性:

  • 修正Rating模型rating字段的默认值:原字段为IntegerField,默认值写为字符串'1'存在隐式转换风险,建议改为整数1
  • 给Rating增加联合唯一约束,避免同一用户对同一内容产生多条重复评分记录

优化后的Rating模型参考:

class Rating(models.Model):
    user = models.ForeignKey(BucketUser, on_delete=models.CASCADE)
    content = models.ForeignKey(Content, on_delete=models.CASCADE)
    rating = models.IntegerField(choices=rating_choices, default=1)

    class Meta:
        constraints = [
            models.UniqueConstraint(fields=['user', 'content'], name='unique_user_content_rating')
        ]

ORM 实现方案

推荐使用annotate+Subquery的写法,逻辑和你提供的子查询SQL完全对齐,性能稳定,取值方便:

from django.db.models import Subquery, OuterRef

# 从GET请求获取传入的user_id,注意做类型转换和合法性校验
target_user_id = int(request.GET.get('user_id'))

# 构造评分子查询
rating_subquery = Rating.objects.filter(
    content=OuterRef('content'),
    user_id=target_user_id
).values('rating')[:1]

# 查询所有Post并注入对应用户的评分字段
post_list = Post.objects.annotate(
    current_user_rating=Subquery(rating_subquery)
).all()

使用说明:

  • 遍历post_list时,每个Post对象会新增一个current_user_rating属性
  • 如果当前传入用户对该Post关联的Content打过分,属性值为对应的评分,否则为None
  • 可通过print(post_list.query)打印生成的SQL,确认和你预期的逻辑一致

如果你需要获取完整的评分对象而非仅评分值,可以使用Prefetch方案:

from django.db.models import Prefetch

target_user_id = int(request.GET.get('user_id'))
post_list = Post.objects.prefetch_related(
    Prefetch(
        'content__rating_set',
        queryset=Rating.objects.filter(user_id=target_user_id),
        to_attr='current_user_rating_list'
    )
).all()

取值时通过post.current_user_rating_list[0].rating获取评分即可。

内容的提问来源于stack exchange,提问作者Rajnish kumar

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 18:06:04