7

I'm attempting to retrieve a filtered list from a MySQL database. The query itself looks fine, but the JSON returned shows this:

[
  {
    "id": "0038",
    "name": "Jane Doe",
    "total_hrs_per_week": 6,
    "timezone": "America/Los_Angeles"
  },
  {
    "id": "0039",
    "name": "John Doe",
    "total_hrs_per_week": 10,
    "timezone": "America/Los_Angeles"
  }
]

when the spec that I need to build to wants this:

{
  "people": [
    {
      "id": "0038",
      "name": "Jane Doe",
      "total_hrs_per_week": 6,
      "timezone": "America/Los_Angeles"
    },
    {
      "id": "0039",
      "name": "John Doe",
      "total_hrs_per_week": 10,
      "timezone": "America/Los_Angeles"
    }
  ]
}

Here's my serializer

class PeopleListSerializer(serializers.ModelSerializer):
    id = serializers.CharField(source='id')
    name =serializers.CharField(source='name')
    total_hrs_per_week = serializers.IntegerField(source='total_hrs_per_week')
    timezone = serializers.CharField(source='timezone')

    class Meta:
        model = models.Person
        fields = ('id','name','total_hrs_per_week','timezone')

Any idea how to wrap the returned results in this way?

EDIT:

I tried wrapping this in another serializer like so

    class PeopleListWrapperSerializer(serializers.Serializer):
        people = PeopleListSerializer(many=True)
         
        class Meta:
            fields = ['people']

But this throws the following error:

Got AttributeError when attempting to get a value for field people on serializer PeopleListWrapperSerializer. The serializer field might be named incorrectly and not match any attribute or key on the Person instance. Original exception text was: 'Person' object has no attribute 'people'.

1
  • Try without fields = ['people'], it will take that field anyway. Maybe it gets confused there. But it's only a guess. Commented May 12, 2016 at 9:11

3 Answers 3

7

You can do that by overriding the list() method.

class PeopleListView(ListAPIView):

    def list(self, request, *args, **kwargs):
        # call the original 'list' to get the original response
        response = super(PeopleListView, self).list(request, *args, **kwargs) 

        # customize the response data
        response.data = {"people": response.data} 

        # return response with this custom representation
        return response 
Sign up to request clarification or add additional context in comments.

4 Comments

This works, however do you know of a solution that keeps any/all of that code within the serializer classes? I'd rather not control serialization from the view.
@L.W. I am currently not aware of a method to do this using just the serializers. Will update my answer upon knowing any such method.
Accepting this as the answer. Couldn't find any other solution either.
Just as an additional resource, it might help to look into pagination classes (which actually do a similar thing to that in the solution above). django-rest-framework.org/api-guide/pagination
1

Depending on how you'll want incoming data and your models, you can:

Comments

0

Old question, but here's an alternative solution that modifies the serializer instead of the view.

The trick is to customize the ListSerializer, as described in the DRF documentation.

Basically, you define a custom ListSerializer...

class MyListSerializer(serializers.ListSerializer):
    def to_representation(self, *args, **kwargs):
        return {'people': super().to_representation(*args, **kwargs)}

... and configure your ModelSerializer to use it:

class PeopleListSerializer(serializers.ModelSerializer):
    ...
    class Meta:
        ...
        list_serializer_class = MyListSerializer

Also see overriding serialization and deserialization behavior.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.