I am building a complicated queryset over a complicated datamodel.
The queryset must return a selection of model objects A
with an annotation ann
.
For computing ann
, I need an auxiliary annotation aux
, but no aux
is allowed to exist in the final results of the queryset.
qs = A.objects.filter(...) # complicated
qs = qs.annotate(aux=...) # complicated
qs = qs.annotate(ann=Case(
When(condition=Q(aux=0),
then Value('some')),
When(condition=Q(aux_gt=0),
then Value('other'))))
How to return qs
with ann
but without aux
?
(Alternatively: If aux
is a count and ann
discriminates zero and non-zero aux
, is there
a better way to approach the whole problem?)
Django 3.2 introduced a feature to solve specifically this:
https://docs.djangoproject.com/en/3.2/ref/models/querysets/#alias
alias()
works like annotate()
except only for other queryset methods such as annotate()
: it doesn't stay in the final output.
qs = A.objects.filter(...)
qs = qs.alias(aux=...) # using alias here instead of annotate
qs = qs.annotate(ann=Case(
When(condition=Q(aux=0),
then Value('some')),
When(condition=Q(aux_gt=0),
then Value('other'))))
A simple, if highly unelegant method is to rename aux
to be called ann
as well.
That way, the second annotation overwrites the first and the first will no longer exist in the output.
qs = A.objects.filter(...) # complicated
qs = qs.annotate(ann=...) # complicated
qs = qs.annotate(ann=Case(
When(condition=Q(ann=0),
then Value('some')),
When(condition=Q(ann_gt=0),
then Value('other'))))
This appears to work. Tested with Django 1.11 on SQlite and PostgreSQL.
But there must be a better way, pleeeease.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With