2017-01-25 86 views
0

轉化我的問題,以一個簡單的域名,假設我繼承了一個Django應用程序與代表測試等級爲字母(「A +」,「A」,「A-」,「數據模型B +「等),我想以百分比形式報告成績平均值,其中{」A +「:100,」A「:95,...}。GROUP BY在Django ORM與合成屬性

玩具模型:

class TestGrade(models.Model): 
    student = ForeignKey(Student) 
    letter_grade = CharField() 
    course = ForeignKey(Course) 

(假設改變模型,做一個遷移 - 明智的解決方案 - 是假表,也許是因爲我們希望有申請信等級的不同映射的靈活性計算得分)

報告這些的時候,我得到了牌號爲使用明顯查詢一個給定的課程,然後應用基於上述映射case語句,像

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')) 

通過ID和得分的元組,這是不符合KeyError: 'score'

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

可怕的死亡並不可怕死了,當然它組我想要的是。

有沒有辦法通過組student_id數據,並與平均綜合值的註釋?

很顯然,我可以在Python做到這一點,但通常的原因,我想這樣做的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> 
+0

不錯,但它不對於我的報道沒有什麼幫助 - 這仍然是每個學生都要強加一個查詢,我必須走出ORM進入Python世界才能使用它。謝謝,不過。 –