Search code examples
djangodjango-rest-frameworkjson-api

How to get "data" rather than "results" with Django Rest Framework ReadOnlyModelViewSet?


I have read this question How to generate JSON-API data attribute vs results attribute in Django Rest Framework JSON API? but the accepted answer does not work for me plus I have a situation not covered there.

I am using Django Rest Framework (3.5.3) to provide an API end point. That end point is based on

class FruitTestReadOnlyViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Fruit.objects.all()
    serializer_class = FruitSerializer
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

The data returned from there is fine except that it has a "results" attribute rather than a "data" attribute.

The question I mentioned above suggests you do this

class FruitTestReadOnlyViewSet(viewsets.ReadOnlyModelViewSet):
    queryset = Fruit.objects.all()
    serializer_class = FruitSerializer
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)
    renderer_classes = (JSONRenderer,)
    parser_classes = (JSONParser,)

but that makes no difference for me and in fact I already have global setting which I believe cover the render and parser aspects like this

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
    'PAGE_SIZE': 10,
    'EXCEPTION_HANDLER': 'rest_framework_json_api.exceptions.exception_handler',
    'DEFAULT_PAGINATION_CLASS':
        'rest_framework_json_api.pagination.PageNumberPagination',
    'DEFAULT_PARSER_CLASSES': (
        'rest_framework_json_api.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    ),
    'DEFAULT_RENDERER_CLASSES': (
        'djangorestframework_camel_case.render.CamelCaseJSONRenderer',
        'rest_framework_json_api.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ),
    'DEFAULT_METADATA_CLASS': 'rest_framework_json_api.metadata.JSONAPIMetadata',
}

So I'm interested to know if someone out there has done this recently and how they did it ?


BTW I have other API endpoints based on ModelViewSet which work fine and which provide a "data" attribute rather than "results" ... here's an example of one of those

class TreeViewSet(viewsets.ModelViewSet):
    """
    API endpoint that allows Tree to be CRUDed.
    """
    queryset = Tree.objects.all()
    serializer_class = TreeSerializer
    authentication_classes = (TokenAuthentication,)
    permission_classes = (IsAuthenticated,)

    def get_queryset(self):
        return Tree.objects.filter(username=self.request.user)

Solution

  • pagination.py

    from collections import OrderedDict
    from rest_framework.response import Response
    
    class Pagination(PageNumberPagination):
    
        def get_paginated_response(self, data):
            return Response(OrderedDict([
                ('count', self.page.paginator.count),
                ('next', self.get_next_link()),
                ('previous', self.get_previous_link()),
                ('data', data)
            ]))
    

    settings.py

    REST_FRAMEWORK = {
        'DEFAULT_PAGINATION_CLASS':
            'path_to_pagination.pagination.Pagination',
    
    }
    

    if you only want apply this to class FruitTestReadOnlyViewSet,not change settings.py and set pagination_class for this class:

    class FruitTestReadOnlyViewSet(viewsets.ReadOnlyModelViewSet):
        pagination_class = Pagination
    

    change default pagination's get_paginated_response method from ('results', data) to ('data', data) will fine.