ChatGPT解决这个技术问题 Extra ChatGPT

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

我想做的是:

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

按姓氏排序作者

有什么建议么?

@RH:那么如何将 AlexMartelli 的答案作为正确的解决方案进行检查? (不是说他需要更多代表,除非他要追赶那个飞碟家伙……)

M
Martin

关于什么

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:这不是我问的,亚历克斯的答案是正确的!
为什么不制作排序键函数lambda x: x.last_name?它更短,更详细,不需要任何导入。
j
jathanism

我只是想说明内置解决方案(仅限 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)并不总是最好的。
它完全符合我的预期:词典排序(如果第一个排序键都是不同的,这有点微不足道)。
i
istruble

这是一种允许截止分数平局的方法。

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) 就会出现。