davidtgq
davidtgq

Reputation: 4010

DjangoRestFramework group objects by a field in the object?

How can objects be grouped by a field in the object, such that all objects with the same value of that field are under one folder/layer/bracket of the JSON?

For example, change from this:

{
    "foo" : [
        {
            "type" : "letter",
            "value" : "x"
        },
        {
            "type" : "letter",
            "value" : "y"
        },
        {
            "type" : "letter",
            "value" : "z"
        },
        {
            "type" : "number",
            "value" : "1"
        },
        {
            "type" : "number",
            "value" : "0"
        }
    ]
}

To this:

{
    "bar" : {
        "letter" : ["x", "y", "z"],
        "number" : ["1", "0"]
    }
}

For context, here is some of my code boiled down to the relevant parts:

class TagSerializer(serializers.ModelSerializer):
    type = serializers.CharField(source='type.type')

    class Meta:
        model = Tag
        fields = ('tag', 'type')

class Tag(models.Model):
    type = models.ForeignKey('TagType', models.CASCADE, 'tags')
    tag = models.CharField(max_length=254, unique=True)

class TagType(models.Model):
    type = models.CharField(max_length=254, unique=True)

In pseudocode, this is what I think would be the first step to accomplishing this. How can this be implemented with or without DRF? Where do I put it?

def TagTypeSerializer():
    types = TagType.objects.all()
    json = []
    for t in types:
        json += t.type
    return json

Upvotes: 1

Views: 1461

Answers (2)

Alex Morozov
Alex Morozov

Reputation: 5993

While it's possible, you'll have to completely override the list() method of your view:

class ListTags(generics.ListAPIView):
    def transform_result(self, data):
        """Your custom data transformations"""
        result = {'tags': set(), 'types': set()}
        for tag in data:
            result['tags'].update(data['tag'])
            result['types'].update(data['type'])
        return result

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())

        page = self.paginate_queryset(queryset)
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(self.transform_result(serializer.data))

        serializer = self.get_serializer(queryset, many=True)
        return Response(self.transform_result(serializer.data))

Upvotes: 3

Linovia
Linovia

Reputation: 20996

Django REST framework serializers don't work like that. You'll likely want to roll your own class to serialize / deserialize.

Upvotes: -2

Related Questions