排序查询集的好方法?- Django
我想做的是这个:
获取得分最高的30位作者(用
Author.objects.order_by('-score')[:30]
这个代码)按照
last_name
(姓氏)对这些作者进行排序
有什么建议吗?
3 个回答
这里有一种方法可以让截止分数出现并列的情况。
author_count = Author.objects.count()
cut_off_score = Author.objects.order_by('-score').values_list('score')[min(30, author_count)]
top_authors = Author.objects.filter(score__gte=cut_off_score).order_by('last_name')
通过这种方式,你可能会得到超过30个作者在top_authors中,而min(30,author_count)
的作用是为了防止作者数量少于30个时出现问题。
我想说明的是,内置的解决方案(仅限SQL)并不总是最好的选择。一开始我以为,因为Django的QuerySet.objects.order_by
方法可以接受多个参数,所以你可以很容易地把它们连在一起使用:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
但是,它并没有像你想的那样工作。举个例子,下面是按得分排序的总统名单(为了更容易阅读,这里只选了前5名):
>>> auths = Author.objects.order_by('-score')[:5]
>>> for x in auths: print x
...
James Monroe (487)
Ulysses Simpson (474)
Harry Truman (471)
Benjamin Harrison (467)
Gerald Rudolph (464)
使用Alex Martelli的解决方案,可以准确地提供按last_name
排序的前5个人:
>>> for x in sorted(auths, key=operator.attrgetter('last_name')): print x
...
Benjamin Harrison (467)
James Monroe (487)
Gerald Rudolph (464)
Ulysses Simpson (474)
Harry Truman (471)
现在来看一下组合后的order_by
调用:
>>> myauths = Author.objects.order_by('-score', 'last_name')[:5]
>>> for x in myauths: print x
...
James Monroe (487)
Ulysses Simpson (474)
Harry Truman (471)
Benjamin Harrison (467)
Gerald Rudolph (464)
正如你所看到的,结果和第一个是一样的,这意味着它并没有像你预期的那样工作。
那关于这个呢
import operator
auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))
在Django 1.4及更新版本中,你可以通过提供多个字段来排序。
参考链接: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by
order_by(*字段)
默认情况下,QuerySet
返回的结果是按照模型的Meta里面的ordering
选项所给出的排序方式来排序的。你可以通过使用order_by
方法来在每个QuerySet
上覆盖这个默认排序。
举个例子:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
上面的结果会先按score
降序排列,然后再按last_name
升序排列。"-score"
前面的负号表示降序排列,而升序排列则是默认的。