Micheal J. Roberts
Micheal J. Roberts

Reputation: 4180

Django REST framework: how to wrap the response with extra fields .... and supply the current response in data field

So, I have the following:

class ObjectViewSet(
    mixins.CreateModelMixin,
    mixins.ListModelMixin,
    mixins.RetrieveModelMixin,
    mixins.DestroyModelMixin,
    viewsets.GenericViewSet
):
    """
    REST API endpoints for Objects.
    """
    serializer_class = ObjectSerializer
    queryset = Object.objects.all()

This returns, say, for a list GET request:

[
    {
        "uuid": "787573a2-b4f1-40df-9e3a-8555fd873461",
    },
    {
        "uuid": "2ab56449-1be1-47d7-aceb-a9eaefa49665",
    }
]

However, how could I slightly alter this response for mixins to be similar to the following:

{
    success: true,
    message: 'Some Extra Useful Message',
    data: [
        {
             "uuid": "787573a2-b4f1-40df-9e3a-8555fd873461",
        },
        {
             "uuid": "2ab56449-1be1-47d7-aceb-a9eaefa49665",
        }
    ]
}

Is this possible, or should I just write my own custom endpoint Response() and not utilise DRF's mixins capability?

So, essentially, switching the custom:

Response(data, status=None, template_name=None, headers=None, content_type=None)

To:


response = {
    'success': true,
    'message': 'Some Extra Useful Message',
    'data': serializer.data
}

Response(response, status=None, template_name=None, headers=None, content_type=None)

Upvotes: 12

Views: 4644

Answers (2)

Swagato
Swagato

Reputation: 126

After long research, I found this useful and most appropriate to use. For such use cases one must refer to this documentation. In your case, you can do the following -

Declare a class renderer.py

from rest_framework.renderers import JSONRenderer
from rest_framework.utils import json


class JSONResponseRenderer(JSONRenderer):
    # media_type = 'text/plain'
    # media_type = 'application/json'
    charset = 'utf-8'

    def render(self, data, accepted_media_type=None, renderer_context=None):
        response_dict = {
            'status': 'failure',
            'data': data,
            'message': '',
        }
        data = response_dict
        return json.dumps(data)

Update your settings.py

REST_FRAMEWORK = {
    # Other code
    'DEFAULT_RENDERER_CLASSES': (
        '<app-name>.renderer.JSONResponseRenderer',
    )
}

Update your ViewSet class

class YourViewSet(viewsets.ModelViewSet):
    # Other code
    renderer_classes = [JSONResponseRenderer]

And you're all set! Also refer to this post more.

Upvotes: 8

Akash Pagar
Akash Pagar

Reputation: 637

You can handle this response format using Middelwares. If based on status code you have a fixed format for a response, then write a middleware.

class ResponseFormatMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        response = self.get_response(request)
        try:
            if (not getattr(response, 'error', False)) and (isinstance(response.data, dict) or isinstance(response.data, list)):
                response.data = {'success': True, 'message':'some message','data': response.data}
        except AttributeError:
            pass
        return response

Middleware is written in CustomMiddleware module as middleware.py, then add

MIDDLEWARE = [
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'corsheaders.middleware.CorsMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    'CustomMiddleware.middleware.ResponseFormatMiddleware', # Added this line
]

in settings.py file.

Upvotes: 3

Related Questions