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


111

我想做的是这样的:

  • 获得得分最高的30位作者(Author.objects.order_by('-score')[:30]

  • 命令作者 last_name


有什么建议?


4
@RH:那么如何检查AlexMartelli的答案作为正确的解决方案呢?(不是他需要更多代表,除非他要
追随

Answers:


190

关于什么

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(*字段)

默认情况下,a返回的结果由模型的Meta中QuerySetordering选项给出的排序元组排序。您可以使用order_by方法基于每个QuerySet重写此方法。

例:

ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]

上面的结果将按score降序排列,然后按last_name升序排列。前面的负号"-score"表示降序。隐含升序。


1
@Alex:格雷兹·亚历克斯!太好了,我准备阅读操作员模块!
RadiantHex 2010年

3
这比Author.objects.order_by('-score','last_name')[:30]更有效吗?
Brian Luft'3

4
@Brian-如果用“更有效”来表示“更正确”,那么是的。:)您的解决方案可以使作者按分数进行排序,并且仅按字母顺序排列具有相同分数的作者(这是辅助键的工作方式)。Alex展示了如何获取结果,然后对结果应用完全不同的排序顺序(使用key = operator.attrgetter定义每个对象的键表达式),这就是OP的要求。
PaulMcG 2010年

@Paul:那不是我问的,Alex的答案是正确的!
RadiantHex

4
为什么不使用排序键功能lambda x: x.last_name?它更短,更详细,并且不需要任何导入。
Krzysztof Szularz

12

我只是想说明一下内置解决方案(仅适用于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的解决方案,该解决方案可准确提供排名前5位的人员last_name

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

如您所见,它与第一个结果相同,这意味着它无法按预期工作。


13
您的结果#3是按分数降序排序,然后按last_name IFF排序具有相同分数的所有对象。问题是结果集中的所有对象都没有相同的分数,因此只有“ -score”会影响排序顺序。尝试将3位作者的得分设置为487,然后再次运行#3。
istruble

是的,我明白。我真的只是想说明内置解决方案(仅SQL)并不总是最好的。
詹森主义2010年

3
它的确符合我的预期:字典顺序(如果第一个排序键都是不同的,这是微不足道的)。
乔纳斯·科尔克(JonasKölker)2012年

5

这是一种允许得分临界值的方法。

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

这样一来,您在top_authors中可能会获得30多位作者,如果您的作者少于30位,则可以在此处找到min(30,author_count)

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.