Adding root element to json response (django-rest-framework)

后端 未结 2 473
隐瞒了意图╮
隐瞒了意图╮ 2020-12-01 01:48

I am trying to determine the best way to add a root element to all json responses using django and django-rest-framework.

I think adding a custom renderer is the bes

相关标签:
2条回答
  • 2020-12-01 02:19

    For posterity, below is the final solution. It has grown slightly from the original as it now reformats paginated results as well.

    Also I should have specified before, that the reason for the JSON root element is for integration with an Ember front end solution.

    serializer:

    from rest_framework.serializers import ModelSerializer
    from api.models import Contact
    
    class ContactSerializer(ModelSerializer):
        class Meta:
            model = Contact
            #define the resource we wish to use for the root element of the response
            resource_name = 'contact' 
            fields = ('id', 'first_name', 'last_name', 'phone_number', 'company')
    

    renderer:

    from rest_framework.renderers import JSONRenderer
    
    class CustomJSONRenderer(JSONRenderer):
        """
            Override the render method of the django rest framework JSONRenderer to allow the following:
            * adding a resource_name root element to all GET requests formatted with JSON
            * reformatting paginated results to the following structure {meta: {}, resource_name: [{},{}]}
    
            NB: This solution requires a custom pagination serializer and an attribute of 'resource_name'
            defined in the serializer
        """
        def render(self, data, accepted_media_type=None, renderer_context=None):
            response_data = {}
    
            #determine the resource name for this request - default to objects if not defined
            resource = getattr(renderer_context.get('view').get_serializer().Meta, 'resource_name', 'objects')
    
            #check if the results have been paginated
            if data.get('paginated_results'):
                #add the resource key and copy the results
                response_data['meta'] = data.get('meta')
                response_data[resource] = data.get('paginated_results')
            else:
                response_data[resource] = data
    
            #call super to render the response
            response = super(CustomJSONRenderer, self).render(response_data, accepted_media_type, renderer_context)
    
            return response
    

    pagination:

    from rest_framework import pagination, serializers
    
    class CustomMetaSerializer(serializers.Serializer):
        next_page = pagination.NextPageField(source='*')
        prev_page = pagination.PreviousPageField(source='*')
        record_count = serializers.Field(source='paginator.count')
    
    class CustomPaginationSerializer(pagination.BasePaginationSerializer):
        # Takes the page object as the source
        meta = CustomMetaSerializer(source='*')
        results_field = 'paginated_results'
    
    0 讨论(0)
  • 2020-12-01 02:25

    Credit to ever.wakeful for getting me 95% of the way there.

    Personally, I wanted to add meta data to every api request for a certain object, regardless of whether or not it was paginated. I also wanted to simply pass in a dict object that I defined manually.

    Tweaked Custom Renderer

    class CustomJSONRenderer(renderers.JSONRenderer):
        def render(self, data, accepted_media_type=None, renderer_context=None):
            response_data = {}
            # Name the object list 
            object_list = 'results'
            try:
                meta_dict = getattr(renderer_context.get('view').get_serializer().Meta, 'meta_dict')
            except:
                meta_dict = dict()
            try:
                data.get('paginated_results')
                response_data['meta'] = data['meta']
                response_data[object_list] = data['results']
            except:
                response_data[object_list] = data
                response_data['meta'] = dict()
                # Add custom meta data
                response_data['meta'].update(meta_dict)
                # Call super to render the response
                response = super(CustomJSONRenderer, self).render(response_data, accepted_media_type, renderer_context)
            return response
    

    Parent Serializer and View Example

    class MovieListSerializer(serializers.ModelSerializer):
        class Meta:
            model = Movie
            meta_dict = dict()
            meta_dict['foo'] = 'bar'
    
    class MovieViewSet(generics.ListAPIView):
        queryset = Movie.objects.exclude(image__exact = "")
        serializer_class = MovieListSerializer
        permission_classes = (IsAdminOrReadOnly,)
        renderer_classes = (CustomJSONRenderer,)
        pagination_serializer_class = CustomPaginationSerializer
        paginate_by = 10
    
    0 讨论(0)
提交回复
热议问题