Django - aggregation with get_FOO_display
Asked Answered
S

3

5

Consider the following:

status = queryset.values('status').annotate(count=Count('status'))

where status field is a CharField with choices. This will result in a list of dictionaries with status DB value along with its count.

Is there a way to aggregate status and show its display value instead? I have looked up the code of _get_FIELD_display which I probably can emulate, but it feels a tad hackish to repeat the framework's internal code.

Sphinx answered 31/7, 2014 at 13:49 Comment(3)
Can you update your question with a input -> expected output example?Margay
@Margay isn't the question clear enough? status -> status aggregated with its display valueSphinx
My bad, I missed that status has choices.Margay
P
6

Without hacking a SQL, you may not achieve this in DB level easily. But, since get_FOO_display operates on Model level, you don't even have to hack _get_FIELD_display or lookup in choices manually (If the following method does not cost your server too much):

YourModel(status=status).get_status_display()

Thus

for s in queryset.values('status').annotate(count=Count('status')):
    print(queryset.model(status=s['status']).get_status_display())
Paella answered 31/7, 2014 at 14:15 Comment(2)
get_FOO_display is added dynamically, it's not available like you put it, unless you meant something else. Can you provide a working example?Sphinx
Thanks, exactly what I wanted.Sphinx
N
1

Take a look at django.contrib.admin.util.display_for_field function. You have to find the field object:

field = queryset.model._meta.get_field('status')
        

Then you can use it as:

display_for_field(status, field)

Or, in your case:

{ unicode(display_for_field(t['status'], field)): t['count']
    for t in queryset.values('taxonomy').annotate(count=models.Count('taxonomy'))}
Necessarian answered 31/7, 2014 at 14:18 Comment(2)
What is taxonomy indicating here? Why doesn't status belong in the values args, given that it is the column he is trying to group by? I'm interested in accomplishing this without an extra for loop.Ire
it seems that display_for_field does exists in django >3 on this library.Keever
K
0

On Django >2, I usually transform the annotated dataset on a list of dict and then apply this function:

dataset =list(MyModel.objects.all().values('status').annotate(count=Count('id')))
dataset = transform_display(dataset,MyModel,'status')

def transform_display(dataset, model_class, field_name):
    for item in dataset:
        field_value = item[field_name]
        instance = model_class(**{field_name: field_value})
        display_method = getattr(instance, f"get_{field_name}_display", None)
        new_value = display_method()
        if new_value:
            item[field_name] = new_value
    return dataset
Keever answered 1/11, 2024 at 13:18 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.