django ORM中具有合成属性的GROUP BY

django ORM中具有合成属性的GROUP BY,django,django-orm,Django,Django Orm,将我的问题转化为一个更简单的领域,假设我继承了一个django应用程序,它的数据模型以字母(“a+”、“a”、“a-”、“B+”等形式表示考试成绩,我想以百分比形式报告成绩平均数,其中{“a+”:100,“a”:95,…} 玩具模型: class TestGrade(models.Model): student = ForeignKey(Student) letter_grade = CharField() course = ForeignKey(Course) (假设改变模型并进

将我的问题转化为一个更简单的领域,假设我继承了一个django应用程序,它的数据模型以字母(“a+”、“a”、“a-”、“B+”等形式表示考试成绩,我想以百分比形式报告成绩平均数,其中{“a+”:100,“a”:95,…}

玩具模型:

class TestGrade(models.Model):
  student = ForeignKey(Student)
  letter_grade = CharField()
  course = ForeignKey(Course)
(假设改变模型并进行迁移——这是明智的解决方案——是不可能的,可能是因为我们希望能够灵活地将字母级别的不同映射应用于数字分数)

为了报告这些,我使用显而易见的查询获得给定课程的分数,然后根据上面的映射应用一个案例语句,类似于

grades.annotate(score=Case(When(letter_grade="A+", then=Value(100)), 
                           When(letter_grade="A", then=Value(95)),
                           ...
                           default=Value(0),
                           output_field=IntegerField)))
现在,我想对学生进行分组,报告他们的平均成绩。不幸的是,标准的djangonic方式是通过

grades.values("student_id").annotate(Avg('score'))
死得很惨,有
keyrerror:“score”

grades.values("student_id", "score").annotate(Avg('score'))
不会可怕地死去,但当然它是按id和分数的元组分组的,这不是我想要的

有没有办法按学生id分组并用合成值的平均值进行注释


显然,我可以在python中这样做,但是出于通常的原因,如果可能的话,我希望在ORM中这样做

你有没有想过把这个逻辑放到模型上?这使得业务逻辑在
Student
对象所在的任何位置都可用。考虑:

class Student(models.Model)
    ...

    @property
    def average_test_grade(self):
        return self.testgrade_set.all().annotate(
            score=Case(
                When(letter_grade="A", then=Value(100)),
                When(letter_grade="A-", then=Value(90)),
                When(letter_grade="B+", then=Value(89)),
                When(letter_grade="B-", then=Value(80)),
                default=Value(0),
                output_field=IntegerField()
            )
        ).aggregate(Avg('score'))
然后在
视图.py
中,您可以使用
.prefetch\u related()
减少查询数量:

最后,在模板中或其他地方:

<ul>
{% for student in students %}
<li>{{ student.average_test_grade }}</li>
{% endfor %}
</ul>
    {学生百分比中的学生百分比}
  • {{学生平均水平{考试成绩}
  • {%endfor%}

Nice,但它对我的报告没有多大帮助——这仍然是对每个学生强加一个查询,我必须走出ORM进入python世界才能使用它。不过谢谢你。
<ul>
{% for student in students %}
<li>{{ student.average_test_grade }}</li>
{% endfor %}
</ul>