分组后的最大注释

时间:2016-10-29 10:27:04

标签: python django

我想为每组(b,c)对计算“a_priority”的最大值。

a_priority是基于案例/将字符串映射到优先级值的注释。

from django.db.models import Max, Case, When, IntegerField
qs = MyObject.objects.all()
qs = qs.annotate(
    a_priority=Case(
        When(a='A', then=1), 
        When(a='S', then=2),
        When(a='Q', then=3),        
        output_field=IntegerField()
    )
)
qs = qs.values("b", "c").annotate(Max("a_priority"))

我收到以下错误:

KeyError: 'a_priority'

我相信qs.values("b", "c")会过滤掉我的注释a_priority。行为与任何实际字段不同,提供字段的最大值。

我的django版本在python 3上是1.10。

2 个答案:

答案 0 :(得分:5)

您是否尝试将Case表达式直接放入Max?这可能是since Django 1.8

from django.db.models import Max, Case, When, IntegerField
qs = MyObject.objects.all()
a_priority=Case(
    When(a='A', then=1), 
    When(a='S', then=2),
    When(a='Q', then=3),        
    output_field=IntegerField()
)
qs = qs.values("b", "c").annotate(max_a_priority=Max(a_priority))

答案 1 :(得分:1)

  

我相信qs.values("b", "c")会过滤掉我的注释a_priority

你是对的! values约束生成的QuerySet中返回的列。但由于QuerySet链接到原始模型,因此您可以使用values中未提供的列进行过滤(例如:qs.values('b', 'c').filter('a'='A'))。

完成任务的最佳方式是PiotrĆwiek的answer。但要使答案更全面(并更好地了解聚合):

  • a_priority中明确包含values

    qs1 = qs.values("b", "c", "a_priority").annotate(max_priority=Max("a_priority")).distinct()
    # Or
    qs2 = qs.values("b", "c", "a_priority").annotate(max_priority=Max("a_priority")).filter(a_priority=F('max_a_priority'))
    
  • 颠倒valuesannotate的顺序:

    qs3 = qs.annotate(max_priority=Max("a_priority")).values("b", "c").distinct()
    

Django docs解释了为什么distinct(或filter)在这里需要,而不是在Piotr的回答中:

  

如果values()子句在annotate()之前,则将使用values()子句描述的分组计算注释。

所以a_priority也包含在GROUP BYqs1的{​​{1}}条款中,因此需要qs2

  

但是,如果annotate()子句位于values()子句之前,将在整个查询集上生成注释。在这种情况下,values()子句仅约束输出时生成的字段。

这解释了distinct。在内部,Django通过qs3执行GROUP BY以获得整个QuerySet的结果。

相关问题