在Django(PostgreSQL)中从Employee模型获取员工多份评估平均分
问题与解决方案
问题场景
现有以下Django模型(注:原模型存在两处拼写错误,已修正):
class Employee(models.Model): name = models.CharField(max_length=100) class Evaluation(models.Model): employee = models.ForeignKey(Employee, on_delete=models.CASCADE) question1 = models.PositiveIntegerField(default=0) question2 = models.PositiveIntegerField(default=0)
员工有多份评估记录,每份记录包含两个问题的得分。当前可以通过Evaluation.objects.annotate(score=F('question1') + F('question2'))获取单份评估的总分,但需要直接从Employee模型查询出每个员工所有评估的平均分。
尝试过两种写法均报错:
- 使用普通子查询时,员工有多份评估会触发错误:
from django.db.models import Avg, F, OuterRef, Subquery score_subquery = Evaluation.objects.annotate(score=F('question1') + F('question2')).filter(employee_id=OuterRef('pk')).values('score') Employee.objects.annotate(avg_score=Avg(Subquery(score_subquery)))
错误信息:
more than one row returned by a subquery used as an expression
- 改用
ArraySubquery适配多行结果,却因PostgreSQL限制报错:
from django.db.models import Avg, F, OuterRef, ArraySubquery score_subquery = Evaluation.objects.annotate(score=F('question1') + F('question2')).filter(employee_id=OuterRef('pk')).values('score') Employee.objects.annotate(avg_score=Avg(ArraySubquery(score_subquery)))
错误信息:
function avg(integer[]) does not exist
需求是仅通过注解实现,不使用存储字段。
可行方案
方案一:利用反向关联直接聚合
这是最简洁的实现方式,借助Django的反向关联(默认名为evaluation_set),直接在Employee的注解中计算平均值:
from django.db.models import Avg, F employees_with_avg = Employee.objects.annotate( avg_score=Avg(F('evaluation__question1') + F('evaluation__question2')) )
Django会自动生成正确的SQL,对每个员工的所有评估记录计算question1+question2的平均值,无需额外子查询。
方案二:子查询内完成聚合计算
如果需要处理更复杂的得分逻辑,可以在子查询中先算出单个员工的平均分,再关联到Employee:
from django.db.models import Avg, F, OuterRef, Subquery # 子查询中先对当前员工的所有评估计算平均分 avg_subquery = Evaluation.objects.filter(employee_id=OuterRef('pk')).annotate( total_score=F('question1') + F('question2') ).aggregate(avg_score=Avg('total_score')).values('avg_score') employees_with_avg = Employee.objects.annotate(avg_score=Subquery(avg_subquery))
这里的核心是用aggregate在子查询内直接得到单个平均值,确保子查询仅返回一行结果,避免了"多行返回"的错误。
原方案失败原因
- 第一种普通子查询写法:子查询返回了该员工的所有评估得分(多行数据),但
Avg作为聚合函数无法直接处理多行子查询的结果,因此触发错误。 - 第二种
ArraySubquery写法:PostgreSQL没有内置的数组平均值计算函数,无法直接对integer[]类型执行avg操作,所以报错。
内容的提问来源于stack exchange,提问作者DrS
相关产品推荐
相关产品推荐

