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

Rad*_*Hex 100 python django django-models

我想要做的是这样的:

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

  • 命令作者 last_name


有什么建议?

Ale*_*lli 176

关于什么

import operator

auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))
Run Code Online (Sandbox Code Playgroud)

在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]
Run Code Online (Sandbox Code Playgroud)

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

  • @Brian - 如果"更高效",你的意思是"更正确",那么是的,它.:)你的解决方案让作者几乎按分数排序,并且只对那些具有相同分数的作者进行按字母顺序排列(这是二级密钥的工作方式).Alex展示了如何获取结果,然后对它们应用完全不同的排序顺序(使用key = operator.attrgetter来定义每个对象的键表达式),这是OP要求的. (4认同)
  • 为什么不使排序键函数`lambda x:x.last_name`?它更短,更冗长,不需要任何导入. (4认同)
  • 这比Author.objects.order_by(' - score','last_name')[:30]更有效吗? (3认同)

jat*_*ism 11

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

ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]
Run Code Online (Sandbox Code Playgroud)

但是,它并不像你期望的那样有效.举个例子,首先是按分数排序的总统名单(选择前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)
Run Code Online (Sandbox Code Playgroud)

使用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)
Run Code Online (Sandbox Code Playgroud)

现在合并后的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)
Run Code Online (Sandbox Code Playgroud)

正如您所看到的,它与第一个结果相同,这意味着它不会像您期望的那样工作.

  • 您的结果#3按分数降序排序,然后按last_name IFF排序,任何对象都具有相同的分数.问题是结果集中的任何对象都没有相同的分数,因此只有'-score'影响排序顺序.尝试将3位作者的得分设置为487并再次运行#3. (12认同)
  • 它完全符合我的预期:词典排序(如果第一个排序键完全不同,这有点'微不足道'). (3认同)

ist*_*ble 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')
Run Code Online (Sandbox Code Playgroud)

这样一来,您在top_authors中可能会获得30多位作者,并且如果您的作者少于30位,那么min(30,author_count)那里就存在。