您需要从“反向”的角度看待这个问题,并使用“注释”。以下是在视图中获得所需输出的方法:
#views.py
from xxx.models import Course, Provider
from django.db.models import Min
from django.shortcuts import render
def home(request):
t = Provider.objects.annotate(best_rating = Min('course__rating')).filter('xxx').order_by('best_rating')
return render(request, 'home.html', {
't':t,
})
那么这里发生了什么:
首先,“annotate”是 Django 执行通常称为“group by”语句的方式。不幸的是,它们根据调用的对象提供不同的结果。因此,在我们的案例中,我们必须关注“每个提供者的最佳课程”,而不是“评价最高的课程及其提供者”。
在我们的.annotate(best_rating = Min('course__rating')) 语句中,内部子句返回最佳课程(假设 1.0 Rating 是最好的,如果相反,则使用 Max())。返回值分配给名为 best_rating 的虚拟模型属性,您可以像任何其他模型成员一样在模板中调用该属性。它只是不会存储在数据库中。
字符串'course__rating' 是一个特殊的字符串。它告诉 Django ORM 我们想要找到最小值的字段。该字符串的格式为"<MODEL>__<FIELD>"。尽管提供者不知道他与课程的关系,但 Django 会为我们执行此反向查找。所以这个字符串基本上是说:“给我所有与提供者有关系的课程的评分字段”
annotate 像许多其他 querySet 方法一样返回一个 QuerySet,因此您可以根据需要过滤和订购新集合。
当然,您也可以在注释之前进行过滤,但请注意,当您进行诸如查找 min() 或 max() 值之类的聚合时,这可能会影响您的最终结果。
基本模板示例:
#home.html
{% for e in t %}
{{ e.name }} {{ e.best_rating }}<br>
{% endfor %}
看看Django Documentation for further information about annotations and reverse lookups。
01.04.2014 更新:
如果你想让你的查询由课程列表驱动,你可以使用以下语句使用 F() 语句
from xxx.models import Course, Provider
from django.db.models import Min, F
from django.shortcuts import render
def home(request):
t = Course.objects.annotate(best_rating = Min('provider__course__rating')).filter(rating = F('best_rating'))
return render(request, 'home.html', {
't':t,
})
此查询将按提供者和课程评分进行注释。但仅此一项就会返回所有提供者,其中包含一个课程评分最低的附加列。所以我们需要根据这个新值过滤每一行。为此,我们需要一个 F() 表达式,它匹配每一行的值。