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

Django ORM:Subquery中用Avg聚合计算电影平均评分报错求助

解决Django中为UserMovieRel记录添加对应电影平均评分的问题

错误原因分析

你遇到的ValueError源于两处问题:

  1. 第一种写法里,avg_ratings[0]会直接触发QuerySet求值,但包含OuterRef的QuerySet只能作为子查询嵌套使用,不能直接索引访问或执行。
  2. 第二种写法里,aggregate()返回的是字典而非QuerySet,而Subquery要求传入合法的QuerySet,同时aggregate上下文无法正确解析OuterRef关联的外部查询。

正确解决方案

方案一:使用Subquery配合分组查询

通过子查询按电影分组计算平均评分,再关联到每条UserMovieRel记录:

from django.db.models import Avg, Subquery, OuterRef

# 定义子查询:筛选当前电影的有效评分,分组计算平均值
rating_subquery = UserMovieRel.objects.filter(
    movie_id=OuterRef("movie_id"),
    rating__isnull=False
).values("movie_id").annotate(
    movie_avg=Avg("rating")
).values("movie_avg")

# 为每条UserMovieRel记录添加对应电影的平均评分
user_movie_records = UserMovieRel.objects.annotate(
    avg_rating=Subquery(rating_subquery)
)
  • values("movie_id")用于按电影分组,确保每个电影仅返回一条平均评分结果
  • 最后values("movie_avg")限制子查询仅返回平均评分字段,让Subquery能正确获取单个值

方案二:使用Window函数(更简洁,Django 2.0+支持)

利用Window函数直接在每条记录上计算同电影的平均评分,无需嵌套子查询:

from django.db.models import Avg, Window, F, Q
from django.db.models.functions import Coalesce

user_movie_records = UserMovieRel.objects.annotate(
    avg_rating=Coalesce(
        Window(
            expression=Avg("rating"),
            partition_by=F("movie_id"),  # 按电影ID分组计算
            filter=Q(rating__isnull=False)  # 排除无评分的记录
        ),
        None  # 当电影无有效评分时返回None
    )
)
  • partition_by=F("movie_id")指定按电影分组计算聚合值
  • Coalesce用于处理无评分场景,避免返回NULL值

验证结果

执行上述代码后,user_movie_records中的每条对象都会带有avg_rating属性,对应其关联电影的有效评分平均值。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.22 08:57:03