Search code examples
pythonjsondjangodjango-rest-frameworkdjango-rest-framework-gis

Including additional data in Django DRF serializer response that doesn't need to be repeated every entry?


Our Django project sends GeoFeatureModelSerializer responses and we want to include an additional value in this response for JS to access. We figured out how to do this in serializers.py:

from rest_framework_gis import serializers as gis_serializers
from rest_framework import serializers as rest_serializers
from core.models import Tablename

class MarkerSerializer(gis_serializers.GeoFeatureModelSerializer):
    new_value = rest_serializers.SerializerMethodField('get_new_value')

    def get_new_value(self, foo): return True

    class Meta:
        fields = ("date", "new_value")
        geo_field = "geom"
        model = Tablename

JS can get this value with geojson.features[0].properties.new_value where const geojson = await response.json(), but it's unnecessarily added with every entry. We'd like for it to be included only once so JS can access it with something like newResponse.new_value and existing functionality can continue getting the same data via newResponse.geojson or similar.

How can we include a single additional value in this response? We thought maybe wrapping our serializer in another, but they seem to be asking a different thing we don't understand. Can we append this somehow? In the serializer can we do something like newResponse = {'new_value': new_value, 'geojson': geojson} somewhere?

We've had a dig through the Django Rest Framework serializers docs and couldn't work it out, so perhaps we're missing something. Other SO threads seem to only ask about adding data for every entry.

edit: we should have mentioned we're using viewsets.py, which looks like:

class MarkerViewSet(viewsets.ReadOnlyModelViewSet):
    bbox_filter_field = "location"
    filter_backends = (filters.InBBoxFilter,)
    queryset = Marker.objects.all()
    serializer_class = MarkerSerializer

Solution

  • Figured it out. This answer is if you're using views, but for viewsets see list() and include this in your viewset:

    def list(self, request, *args, **kwargs):
        queryset = self.filter_queryset(self.get_queryset())
        serializer = self.get_serializer(queryset, many=True)
    
        # idk what this code does but as we're overriding probably best to keep it
        page = self.paginate_queryset(queryset) 
        if page is not None:
            serializer = self.get_serializer(page, many=True)
            return self.get_paginated_response(serializer.data)
    
        # adjust things as desired here like so, defining self.new_value elsewhere
        returned_object = {'new_value': self.new_value, 'geojson': serializer.data} 
        
        return Response(returned_object)