Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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)
like image 995
Micheal J. Roberts Avatar asked Feb 13 '20 14:02

Micheal J. Roberts


People also ask

How do you pass extra context data to Serializers in Django REST framework?

In function based views we can pass extra context to serializer with "context" parameter with a dictionary. To access the extra context data inside the serializer we can simply access it with "self. context". From example, to get "exclude_email_list" we just used code 'exclude_email_list = self.

Why do we need Serializers in Django REST framework?

Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.


2 Answers

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.

like image 69
Swagato Avatar answered Oct 30 '22 23:10

Swagato


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.

like image 30
Akash Pagar Avatar answered Oct 30 '22 22:10

Akash Pagar