Python 排序查询集的好方法德扬戈

Python 排序查询集的好方法德扬戈,python,django,django-models,Python,Django,Django Models,我想做的是: 获取得分最高的30位作者(Author.objects.order_by('-score')[:30]) 按作者姓名排序 有什么建议吗?怎么样 import operator auths = Author.objects.order_by('-score')[:30] ordered = sorted(auths, key=operator.attrgetter('last_name')) 在Django 1.4及更新版本中,您可以通过提供多个字段来订购。 参考: 订购人

我想做的是:

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

  • 按作者姓名排序


有什么建议吗?

怎么样

import operator

auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))
在Django 1.4及更新版本中,您可以通过提供多个字段来订购。
参考:

订购人(*字段)

默认情况下,
QuerySet
返回的结果按模型元中的
ordering
选项给出的排序元组排序。通过使用
order\u by
方法,您可以在每个查询集的基础上覆盖此选项

示例:

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

上述结果将按
得分
降序排列,然后按
姓氏
升序排列。
“-score”
前面的负号表示降序。这意味着升序。

这里有一种方法,允许在截止分数上打成平局

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多位作者,
min(30位,作者计数)
,以防您的作者少于30位。

我只是想说明,内置解决方案(仅SQL)并不总是最好的解决方案。起初我认为,因为Django的
QuerySet.objects.order\u by
方法接受多个参数,所以可以很容易地将它们链接起来:

ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
但是,它并不像你所期望的那样有效。举个例子,首先是按分数排序的总统列表(选择前5名以便阅读):

使用Alex Martelli的解决方案,该解决方案准确地提供了按姓氏排序的前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\u 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)

正如您所看到的,它的结果与第一个结果相同,这意味着它没有像您预期的那样工作

@Alex:grazie Alex!太好了,我要去读关于操作员模块的书了!这比Author.objects.order_by('-score',last_name')[:30]更高效吗?@Brian-如果“更高效”的意思是“更正确”,那么是的,它是:)您的解决方案基本上按照分数对作者进行排序,并且只对分数相同的作者按字母顺序排列(这就是副键的工作方式)。Alex演示了如何获取结果,然后对结果应用完全不同的排序顺序(使用key=operator.attrgetter定义每个对象的键表达式),这正是OP要求的。@Paul:我不是这么问的,Alex的答案是正确的!为什么不使用排序键功能
lambda x:x.last_name
?它更简短,更详细,不需要任何导入。@RH:那么检查AlexMartelli的答案作为正确的解决方案如何?(并不是说他需要更多的重复,除非他在追那个双向飞碟选手……)你的结果是按分数递减排序,然后按姓氏排序,如果任何物体的分数相同。问题是结果集中没有一个对象具有相同的分数,因此只有“-score”影响排序顺序。试着把3位作者的分数设为487,然后再跑3分。是的,我理解。我真的只是想说明,内置解决方案(仅限SQL)并不总是最好的解决方案。它完全符合我的预期:字典排序(如果第一个排序键都是不同的,这有点“微不足道”)。
>>> 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)