Максимум аннотации после группы по

Я хотел бы вычислить максимум "a_priority" для каждой группы (b, c) пар.

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 - 1.10 на Python 3.

2 ответа

Вы пытались положить Case выражение прямо в Max? Это возможно начиная с 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))

Я верю qs.values("b", "c") отфильтровывает мою аннотацию a_priority,

Ты прав! values ограничить столбцы, которые возвращаются в результирующем QuerySet. Но так как QuerySet связан с исходной моделью, вы можете фильтровать, используя столбцы, не предоставленные в values (Например: qs.values('b', 'c').filter('a'='A')).

Лучший способ выполнить вашу задачу - это ответ Петра Свика. Но чтобы сделать ответы более полными (и лучше узнать агрегаты):

  • явно включить 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'))
    
  • обратный порядок values а также annotate:

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

Django документы объясняют, почему distinct (или же filter) требуется здесь, а не в ответе Петра:

Если предложение values ​​() предшествует annotate(), аннотация будет вычислена с использованием группировки, описанной предложением values ​​().

Так a_priority также включен в GROUP BY пункт в qs1 а также qs2отсюда distinct необходимо.

Однако если предложение annotate () предшествует предложению values ​​(), аннотации будут создаваться по всему набору запросов. В этом случае предложение values ​​() ограничивает только поля, сгенерированные на выходе.

Это объясняет qs3, Внутренне Джанго делает GROUP BY от id чтобы получить результаты по всему QuerySet.

Другие вопросы по тегам