对查询集进行排序的好方法? - 姜戈
Posted
技术标签:
【中文标题】对查询集进行排序的好方法? - 姜戈【英文标题】:Good ways to sort a queryset? - Django 【发布时间】:2011-01-25 15:32:15 【问题描述】:我想要做的是:
获得得分最高的 30 位作者 (Author.objects.order_by('-score')[:30]
)
按last_name
排序作者
有什么建议吗?
【问题讨论】:
@RH:那么检查 AlexMartelli 的答案作为正确的解决方案怎么样? (不是说他需要更多的代表,除非他要去追那个 Skeet 家伙......) 【参考方案1】:怎么样
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(*fields)
默认情况下,QuerySet
返回的结果按模型元中ordering
选项给出的排序元组排序。您可以使用 order_by
方法在每个 QuerySet 的基础上覆盖它。
示例:
ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
上述结果将按score
降序排列,然后按last_name
升序排列。 "-score"
前面的负号表示降序。隐含升序。
【讨论】:
@Alex:感恩亚历克斯!太好了,我要去阅读有关操作员模块的信息! 这比 Author.objects.order_by('-score', 'last_name')[:30] 效率高吗? @Brian - 如果“更高效”的意思是“更正确”,那么是的,它。 :) 您的解决方案使作者几乎按分数排序,并且仅按字母顺序排列具有相同分数的那些作者(这是辅助键的工作方式)。 Alex 展示了如何获取结果,然后对它们应用完全不同的排序顺序(使用 key=operator.attrgetter 定义每个对象的键表达式),这正是 OP 所要求的。 @Paul:这不是我问的,Alex 的答案是正确的! 为什么不做排序键功能lambda x: x.last_name
?它更短,更详细,不需要任何导入。【参考方案2】:
我只是想说明内置解决方案(仅限 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)
如您所见,它与第一个结果相同,这意味着它不会像您预期的那样工作。
【讨论】:
您的结果 #3 是按分数降序排序,然后按姓氏排序 IFF 任何对象具有相同的分数。问题是结果集中的所有对象都没有相同的分数,因此只有“-score”会影响排序顺序。尝试将 3 authors score 设置为 487 并再次运行 #3。 是的,我明白了。我真的只是想说明内置解决方案(仅限 SQL)并不总是最好的。 它完全符合我的预期:字典顺序(如果第一个排序键完全不同,这有点'微不足道)。【参考方案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')
通过这种方式,您可能会在 top_authors 中获得超过 30 位作者,如果您的作者少于 30 位,min(30,author_count)
就在那里。
【讨论】:
以上是关于对查询集进行排序的好方法? - 姜戈的主要内容,如果未能解决你的问题,请参考以下文章