1

I need a nested serializer in django. I have the following serializer that works:

class LocationSerializer(serializers.ModelSerializer):
    coordinate = serializers.SerializerMethodField()
    message = serializers.SerializerMethodField()

    def get_message(self, instance: models.Location):
        if len(instance.message) > 1:
            return instance.message
        return None

    def get_coordinate(self, instance: models.Location):
        if instance.point:
            return {"latitude": instance.point.y, "longitude": instance.point.x}

    class Meta:
        model = models.Location
        fields = ('id', 'street', 'zip', 'phone', 'coordinate', 'message')

The json this serializer produces needs to be wrapped in a a json object like this:

{
    "locations": //here comes the serialized data
}

I tried it the following way with another serializer that has the serializer above in a field:

class LocationResponseSerializer(serializers.Serializer):

    locations = LocationSerializer(many=True)

But when I trie to use this serializer I always get the following error:

 The serializer field might be named incorrectly and not match any attribute or key on the `Location` instance.
 Original exception text was: 'Location' object has no attribute 'locations'.

What am I doing wrong? Just wrapping it in a response object works, but is not a solution because it looks like this is not supported by the swagger frameworks that work with Django.

Thanks for the help!

Edit: This is the list method of my view:

def list(self, request, *args, **kwargs):
    # update_compartments()
    queryset = Location.objects.filter(hidden=False).all()
    serializer = LocationResponseSerializer(queryset, many=True)
    return Response(serializer.data)
Materno
  • 343
  • 8
  • 20
  • What does your view code look like? How are you using the `LocationResponseSerializer`? – slider Oct 10 '19 at 17:25
  • I added the list method of my Viewset in the post above. The view itself extends from viewsets.ViewSet – Materno Oct 11 '19 at 07:26

1 Answers1

2

The issue is that this serializer receives data from Location.objects.filter(hidden=False).all() queryset, so it serializes those one by one.

class LocationResponseSerializer(serializers.Serializer):
    locations = LocationSerializer(many=True)

If wrapping the response doesn't work well for you, you might try

class LocationResponseSerializer(serializers.Serializer):
    locations = LocationSerializer(source="*")

but this is not what you want as well, since it will generate locations for each record in queryset

Another option would be to your view

def get_queryset(self):
    locations = Location.objects.filter(hidden=False).all()
    return { 'locations': locations }

or change your list method to smt like

def list(self, request, *args, **kwargs):
    # update_compartments()
    data = Location.objects.filter(hidden=False).all()
    queryset = { 'locations': data }
    serializer = LocationResponseSerializer(queryset)
    return Response(serializer.data)

But you'll need to also write a custom paginator probably in this case, since it won't work out of the box if you'll need it

Hope that helps

ihoryam
  • 1,941
  • 2
  • 21
  • 24