【问题标题】:GROUP BY in django ORM with synthetic attributes具有合成属性的 Django ORM 中的 GROUP BY
【发布时间】:2017-06-10 21:44:08
【问题描述】:

将我的问题转换为更简单的领域,假设我继承了一个 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)))

现在,我想对学生进行 GROUP BY 并报告他们的平均成绩。不幸的是,标准的 djangonic 方式来做 GROUP BY,

grades.values("student_id").annotate(Avg('score'))

死于KeyError: 'score'

grades.values("student_id", "score").annotate(Avg('score'))

不会死得很惨,但它当然是按 id 和 score 的元组分组的,这不是我想要的。

有没有办法按 student_id 分组并用合成值的平均值进行注释?

显然,我可以在 python 中执行此操作,但出于通常的原因,如果可能的话,我想在 ORM 中执行此操作。

【问题讨论】:

    标签: django django-orm


    【解决方案1】:

    你有没有想过把这个逻辑放在模型上?这使得业务逻辑在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'))
    

    然后在您的views.py 中,您可以使用.prefetch_related() 减少查询次数:

    students = Student.objects.prefetch_related('testgrade_set').all()
    

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

    <ul>
    {% for student in students %}
    <li>{{ student.average_test_grade }}</li>
    {% endfor %}
    </ul>
    

    【讨论】:

    • 很好,但它对我的报告没有多大帮助——这仍然是对每个学生施加一个查询,我必须从 ORM 进入 python 世界才能使用它。不过,谢谢。
    猜你喜欢
    • 2014-09-05
    • 2021-08-01
    • 2019-02-28
    • 1970-01-01
    • 2016-02-04
    • 2013-03-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多