2010-03-09 24 views
69

什么,我试图做的是这样的:排序查询集的好方法? - Django的

  • 通过last_name


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

  • 顺序作者

    有什么建议吗?

  • +2

    @RH:那么如何检查AlexMartelli的答案是正确的解决方案?(并不是说他需要更多的代表,除非他追求那个Skeet家伙......) – PaulMcG 2010-03-10 01:42:00

    +0

    简单而重要。这工作。谢谢! – Shilpa 2016-08-27 13:31:21

    回答

    125

    什么

    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(*字段)

    默认情况下,由QuerySet返回的结果是通过在模型中的元的ordering选项给出的排序元组排序。您可以通过使用order_by方法在基于每个QuerySet的基础上覆盖此值。

    实施例:

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

    结果上述将由score降序由last_name升序排序,然后。 "-score"前的负号表示降序。暗示升序。

    +0

    @Alex:grazie alex!那真是太好了,我正在阅读关于操作员模块的内容! – RadiantHex 2010-03-09 21:52:35

    +3

    这是否比Author.objects.order_by(' - score','last_name')[:30]更高效? – 2010-03-10 00:45:59

    +4

    @布莱恩 - 如果用“更高效”的意思是“更正确”,那么是的,它的。 :)你的解决方案使得作者几乎按照分数排序,并且只能按照相同分数(这是次要密钥的工作方式)来使这些作者字母化。 Alex展示了如何获取结果,然后对它们应用完全不同的排序顺序(使用key = operator.attrgetter来定义每个对象的关键表达式),这是OP要求的。 – PaulMcG 2010-03-10 01:39:22

    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多个作家这种方式和min(30,author_count)有柜面你有少于30名作者。

    9

    我只是想说明内置解决方案(仅限于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) 
    

    使用亚历马尔泰利的解决方案,准确地提供了前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) 
    

    现在合并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) 
    

    正如你可以看到它是相同的结果作为第一位的,这意味着它不工作,你会Ë xpect。

    +10

    您的结果#3按排序降序排列,然后按last_name排序IFF任何对象都有相同的分数。问题是结果集中没有任何对象具有相同的分数,因此只有'-score'影响排序顺序。尝试设置3个作者的分数为487并再次运行#3。 – istruble 2010-03-10 01:52:05

    +0

    是的,我明白这一点。我只是想说明内置解决方案(仅限于SQL)并不总是最好的解决方案。 – jathanism 2010-03-10 14:24:21

    +0

    +1违反直觉的ORDER BY子句的好例子 – PaulMcG 2010-03-10 17:12:52