对查询集进行排序的好方法? - 姜戈

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) 就在那里。

【讨论】:

以上是关于对查询集进行排序的好方法? - 姜戈的主要内容,如果未能解决你的问题,请参考以下文章

使用日期对查询集进行排序

按添加的字段对查询集进行排序

如何使用 django 和 htmx 对查询集进行排序?

根据列表的顺序对过滤后的查询集进行排序

对搜索结果的查询集进行排序并通过 ajax 呈现

如何编写 sql 查询对数据集进行排序或分组