Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DRF: Manipulating serializer field layout

I have a model that represents a house:

class House(models.Model):
    name = models.CharField(...)
    long = models.FloatField(...)
    lat = models.FloatField(...)

and a serializer to return a list of houses in their most basic representation:

class HouseSerializer(serializers.ModelSerializer):
    class Meta:
        model = House
        fields = ('id', 'name')    

and the view

class HouseList(generics.ListAPIView):
    queryset = House.objects.all()
    serializer_class = HouseSerializer

this works fine. I can visit /api/house/ and I see a json list of houses:

{ 
    'id': 1,
    'name': 'Big House'
},
{
    'id': 1
    'name': 'Small House',
}...

Now I want to create a second view/resource at /api/maps/markers/ that returns my houses as a list of Google-Map-Friendly markers of the format:

{ 
    'id': 1,
    'long': ...,
    'lat': ...,
    'houseInfo': {
        'title': "Big House",
    }
} ...

I can foresee two approaches:

  • perform this as a separate serializer (using the same view as before) and mapping out the alternative field layout.
  • perform this as a separate view (using the same serializer as before) and simply layout the fields before creating a Response

but in neither approach am I clear on how to go about it nor which approach is preferable?

like image 665
Timmy O'Mahony Avatar asked Mar 18 '23 20:03

Timmy O'Mahony


1 Answers

Answer 1

Looks to me like you need both - different view and serializer.

Simply because the view endpoint is not a sub-url of the first one, so they are not related - different view, even if they use the same model.

And different serializer - since you have a different field layout.

Not really sure how complicated is your case, but any code duplication can probably be solved by mixins anyway.

Answer 2

Depending on the use case:

  • if you also need to write data using the same struct, you need to define your own field class and handle the parsing correctly
  • if it's just reading data, you should be fine with this:

    class HouseGoogleSerializer(HouseSerializer):
        houseInfo = serializers.SerializerMethodField('get_house_info')
    
        class Meta:
            model = House
            fields = [...]
    
        def get_house_info(self, obj):
            return {'title': obj.name}
    

    where HouseSerializer is your base house serializer.

like image 145
mariodev Avatar answered Mar 27 '23 21:03

mariodev