I am trying to get display names of choices when using annotate, but I haven't been able to figure out. I have the following query:
Survey.objects.values('what').annotate(count=Count('why')).order_by()
And the result is:
[{'count': 34, 'what': u'a'},
{'count': 39, 'what': u'c'},
{'count': 40, 'wat': u'p'}]
But I want something that displays the name of the choice field and not the key:
[{'count': 34, 'what': u'appreciative'},
{'count': 39, 'what': u'creative'},
{'count': 40, 'wat': u'promising'}]
I tried get_what_display (as mentioned on the docs and other stackoverflow answers on this topic), but django throws an error. i.e the following doesn't seem to work
Survey.objects.values('get_what_display').annotate(count=Count('why')).order_by()
To accomplish this without iterating over the queryset you can use a conditional expression to annotate with the display attribute. Annotated attributes are available to use in .values()
.
from django.db.models import Case, CharField, Value, When
choices = dict(Survey._meta.get_field('what')[0].flatchoices)
whens = [When(what=k, then=Value(v)) for k, v in choices.items()]
survey_counts = (
Survey.objects
.annotate(get_what_display=Case(*whens, output_field=CharField()))
.values('get_what_display')
.annotate(count=Count('why'))
.order_by()
)
Building upon @bdoubleu's answer, I wrote the following generic conditional expression:
# myapp/utils.py
from django.db.models import Case, CharField, Value, When
class WithChoices(Case):
def __init__(self, model, field, condition=None, then=None, **lookups):
choices = dict(model._meta.get_field(field).flatchoices)
whens = [When(**{field: k, 'then': Value(v)}) for k, v in choices.items()]
return super().__init__(*whens, output_field=CharField())
# example usage
from myapp.utils import WithChoices
from myapp.models import MyModel
MyModel.objects.annotate(what_with_choices=WithChoices(MyModel, 'what')).values('what_with_choices')
There's probably a cleaner way to build that doesn't require passing the model
arg to WithChoices but, hey, this works.
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