Django ORM:Subquery中用Avg聚合计算电影平均评分报错求助
解决Django中为UserMovieRel记录添加对应电影平均评分的问题
错误原因分析
你遇到的ValueError源于两处问题:
- 第一种写法里,
avg_ratings[0]会直接触发QuerySet求值,但包含OuterRef的QuerySet只能作为子查询嵌套使用,不能直接索引访问或执行。 - 第二种写法里,
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
相关产品推荐
相关产品推荐

