我被困在django的查询中。 我有两个模型,
Class Course(models.Model):
provider = ForeignKey(Provider)
rating = FloatField()
Class Provider(models.Model):
...
我想查询课程列表,但同一个提供者不能提供两门课程。也就是说,只选择每个提供者最相关的课程。 我这样做了,
Course.objects.filter(xxxx).distinct('provider')
这可行,但如果我想将order_by添加到此查询,例如
Course.objects.filter(xxxx).distinct('provider').order_by('rating')
发生错误。在django文档中, order_by()中的字段必须以distinct()中的字段开头,顺序相同。
然而,我仍然找不到任何其他解决方法来做同样的事情。
任何想法? 非常感谢你。
答案 0 :(得分:0)
您需要从反向'中查看此问题。透视和使用" annotage"。以下是您在视图中获得所需输出的方式:
#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等级是最好的,如果是相反的方式则使用Max()
)。返回值被分配给名为best_rating的虚拟模型属性,您可以像任何其他模型成员一样在模板中调用该属性。它只是不会存储在数据库中。
字符串'course__rating'
是一个特殊字符串。它告诉Django ORM我们想要找到哪个字段的最小值。此字符串的格式为"<MODEL>__<FIELD>"
。虽然提供者不知道他与课程的关系,但Django会为我们进行反向查找。所以这个字符串基本上说:&#34;给我所有与提供者有关系的课程的评级字段&#34;
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()表达式,它匹配每一行的值。
答案 1 :(得分:0)
对您的问题实际上有一个更简单的解决方案。简单地做Django告诉你的事情:
Course.objects.filter(xxxx).distinct('provider').order_by('provider', 'rating')
我不确切知道幕后发生了什么,但这对我有用。只需将distinct字段添加为 first order参数即可。之后,您可以添加自定义订购。除了相关/外键排序。例如。这不起作用:
Course.objects.filter(xxxx).distinct('provider').order_by('provider', 'some_model__created')
第二部分不是你要求的,但这是一个典型的错误 - 所以记住这一点。此外,在模型中使用“class Meta”排序时,这将不起作用。