Максимум аннотации после группы по
Я хотел бы вычислить максимум "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.