how overwrite Response class in django rest framework ( DRF )?

发布于 2021-01-29 14:09:41

I want to overwrite Response class of django rest framework so that response
back responsive dictionary contain three parameter message, status and
data

Hello dears all

I try to change Response Class in DRF to pass two extra parameter (
message, status ) plus data provide by DRF serializer. message pass the
message like Done, User Created or etc and status pass the message like
fail or success or etc message and this message useful for reserve special
code between frontend and backend.

I want to if don’t set this parameter return empty character or null result
back to client side

for example in success mode:

{
    'data': {
        'value_one': 'some data',
        'value_two': 'some data',
        'value_three': [
                'value', 'value', 'value'
            ],
        },
    }
    'message': 'Done',
    'status': 'success',
}

and in failure mode:

{
    'data': ['any error message raise by serializer',]
    'message': 'Create User Failed',
    'status': 'failure',
}

I search about my question and found this solution:

if i inheritance DRF Response Class in my class and overwrite __init__
method and get message, data and status in this method and call init of
parent with own data structure and use this responsive class in my
functionality like this implement:

from rest_framework.response import Response


class Response(Response):

    def __init__(self, data=None, message=None, data_status=None, status=None,
                template_name=None, headers=None,
                exception=False, content_type=None):

        data_content = {
            'status': data_status,
            'data': data,
            'message': message,
        }
        super(Response, self).__init__(
            data=data_content,
            status=status,
            template_name=template_name,
            headers=headers,
            exception=exception,
            content_type=content_type
        )

in success mode call:

return Response(data=serializer.data, message='Done', data_status='success', status=200)

in failure mode call:

return Response(data=serializer.errors, message='Create User Failed', data_status='failure', status=400)

and use own Response class in all views class we had problem in this
solution: if we use GenericViews Class must be overwrite all http methods we
used in view’s logic and call own class and this is DRY!!


and other solution i found. in serialized layer, we have abstract method def to_representation(self, instance): in Serializer class and implement in
other class like ModelSerializer class inheritance Serializer and if we
overwrite this method in our serializer class and re fetch data before send to
view layer, implement like:

from collections import OrderedDict

class OurSerializer(serializer.ModelSerializer):

....

    def to_representation(self, instance):
        data = super(serializers.ModelSerializer, self).to_representation(instance)
        result = OrderedDict()
        result['data'] = data
        result['message'] = 'Done'
        result['status'] = 'sucssed'
        return result

this solution solve above problem but we have two problem again

one: if we use nested serializer and we had overwrite this function in
serializer class return bad data like:

{
    'data': {
        'value_one': 'some data',
        'value_two': 'some data',
        'value_three': {
            'data': [
                'value', 'value', 'value'
            ],
            'message': 'Done',
            'status': 'sucssed',
        },
    }
    'message': 'Done',
    'status': 'sucssed',
}

and message and status repeated and structure not pretty for client

and two: we cant handle exception in this mode and just way to handle
exception just with middleware class like this DRF Exception
Handling
and this isn’t useful way, we can’t handle any type of
error occurs in view and generate comfortable separate message and status.

IF there’s another good solution to this question, please guide me.

thanks :)

关注者
0
被浏览
159
1 个回答
  • 面试哥
    面试哥 2021-01-29
    为面试而生,有面试问题,就找面试哥。

    To resolve this, best practice (that DRF has proposed) is to use ‘renderer’
    classes. A renderer manipulates and returns structured response.

    Django uses renderers like Template Renderer and DRF
    benefits this feature and provides API Renderers.

    To do so, you could provide such this renderer in a package (e.g.
    app_name.renderers.ApiRenderer):

    from rest_framework.renderers import BaseRenderer
    from rest_framework.utils import json
    
    
    class ApiRenderer(BaseRenderer):
    
        def render(self, data, accepted_media_type=None, renderer_context=None):
            response_dict = {
                'status': 'failure',
                'data': {},
                'message': '',
            }
            if data.get('data'):
                response_dict['data'] = data.get('data')
            if data.get('status'):
                response_dict['status'] = data.get('status')
            if data.get('message'):
                response_dict['message'] = data.get('message')
            data = response_dict
            return json.dumps(data)
    

    And then in your settings file:

    REST_FRAMEWORK = {
        ...
        'DEFAULT_RENDERER_CLASSES': (
            'app_name.renderers.ApiRenderer',
        ),
        ...
    }
    

    By this action all views that extend DRF generic views will use renderer. If
    you needed to override setting you can use renderer_classes attribute for
    generic view classes and @renderer_classes decorator for api view functions.

    A comprehensive renderer class to override is available at
    <virtualenv_dir>/lib/python3.6/site-packages/rest_framework/renderers.py.



知识点
面圈网VIP题库

面圈网VIP题库全新上线,海量真题题库资源。 90大类考试,超10万份考试真题开放下载啦

去下载看看