how overwrite Response class in django rest framework ( DRF )?
This would be more a more robust solution, as it can be used with Generic Views hassle free.
In case of Generic views, the data argument we receive in the render() method is sent automatically by the generic view itself (if not overriding the methods, which will be against DRY), so we cannot handle it, as it does in the accepted answer.
Also, the checks in render() can be easily altered as per the needs (Eg., handling no-2XX status codes in this solution).
from rest_framework.renderers import JSONRenderer
class CustomRenderer(JSONRenderer):
def render(self, data, accepted_media_type=None, renderer_context=None):
status_code = renderer_context['response'].status_code
response = {
"status": "success",
"code": status_code,
"data": data,
"message": None
}
if not str(status_code).startswith('2'):
response["status"] = "error"
response["data"] = None
try:
response["message"] = data["detail"]
except KeyError:
response["data"] = data
return super(CustomRenderer, self).render(response, accepted_media_type, renderer_context)
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
.