Django-REST-Framework “GroupBy” ModelSerializer

2019-07-28 10:42发布

问题:

I have the following situation

class MyModel(models.Model):
    key = models.CharField(max_length=255)
    value = models.TextField(max_length=255)
    category = models.CharField(max_length=4)
    mode = models.CharField(max_length=4)

the fields key, category and mode are unique together. I have the following objects:

    m1 = MyModel(key='MODEL_KEY', value='1', category='CAT_1' mode='MODE_1')
    m2 = MyModel(key='MODEL_KEY', value='2', category='CAT_1' mode='MODE_2')
    m3 = MyModel(key='MODEL_KEY', value='1', category='CAT_2' mode='MODE_1')
    m4 = MyModel(key='MODEL_KEY', value='2', category='CAT_2' mode='MODE_2')

I want to expose an API that will group by key and category so the serialized data will look something like this:

{
    "key": "MODEL_KEY",
    "category": "CAT_1"
    "MODE_1": { "id": 1, "value": "1" }
    "MODE_2": { "id": 2, "value": "2" }
},
{
    "key": "MODEL_KEY",
    "category": "CAT_2"
    "MODE_1": { "id": 3, "value": "1" }
    "MODE_2": { "id": 4, "value": "2" }
}

Is there any way of doing this in django rest framework with ModelSerializer.

回答1:

There is module that allows you to group Django models and still work with a QuerySet in the result: https://github.com/kako-nawao/django-group-by

Using the above to form your queryset:

# Postgres specific!
from django.contrib.postgres.aggregates.general import ArrayAgg

qs = MyModel.objects.group_by('key', 'category').annotate(
        mode_list=ArrayAgg('mode')).order_by(
        'key', 'category').distinct()

You can then access the properties key, category and mode_list on the resulting QuerySet items as attributes like qs[0].mode_list. Therefore, in your serializer you can simply name them as fields.

The model_list field might require a SerializerMethodField with some custom code to transform the list.

Note that you need an aggregation if you don't want to group by mode, as well.