排序查询集的好方法?- Django

165 投票
3 回答
193665 浏览
提问于 2025-04-15 20:13

我想做的是这个:

  • 获取得分最高的30位作者(用 Author.objects.order_by('-score')[:30] 这个代码)

  • 按照 last_name(姓氏)对这些作者进行排序


有什么建议吗?

3 个回答

6

这里有一种方法可以让截止分数出现并列的情况。

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个时出现问题。

18

我想说明的是,内置的解决方案(仅限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)

正如你所看到的,结果和第一个是一样的,这意味着它并没有像你预期的那样工作。

264

那关于这个呢

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"前面的负号表示降序排列,而升序排列则是默认的。

撰写回答