In my project I use DRF as backend and Angular as frontend.
Django==1.10 djangorestframework==3.7.1
I need all responses from DRF to be in the following format.
{
"status": "", // 200,400,.....etc
"error": "", // True, False
"data": [], // data
"message": "" // Success messages
}
Currently it is in
[
{
"id": 1,
"name": ""
},
{
"id": 2,
"name": ""
}
]
it should be
{
"status": "200",
"error": "False",
"data": [
{
"id": 1,
"name": ""
},
{
"id": 2,
"name": ""
}
],
"message": "Success"
}
for this i have written a custom viewset and overridden the functions list, detail, create, update
class ResponseModelViewSet(viewsets.ModelViewSet):
def list(self, request, *args, **kwargs):
queryset = self.filter_queryset(self.get_queryset())
page = self.paginate_queryset(queryset)
if page is not None:
serializer = self.get_serializer(page, many=True)
return self.get_paginated_response(serializer.data)
serializer = self.get_serializer(queryset, many=True)
custom_data = {
"status": True,
"error": False,
"message": 'message',
"data": serializer.data
}
return Response(custom_data)
def create(self, request, *args, **kwargs):
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
self.perform_create(serializer)
headers = self.get_success_headers(serializer.data)
custom_data = {
"status": True,
"error": False,
"message": 'message',
"data": serializer.data
}
return Response(custom_data, status=status.HTTP_201_CREATED, headers=headers)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
custom_data = {
"status": True,
"error": False,
"message": 'message',
"data": serializer.data
}
return Response(custom_data)
def update(self, request, *args, **kwargs):
partial = kwargs.pop('partial', False)
instance = self.get_object()
serializer = self.get_serializer(instance, data=request.data, partial=partial)
serializer.is_valid(raise_exception=True)
self.perform_update(serializer)
if getattr(instance, '_prefetched_objects_cache', None):
# If 'prefetch_related' has been applied to a queryset, we need to
# forcibly invalidate the prefetch cache on the instance.
instance._prefetched_objects_cache = {}
custom_data = {
"status": True,
"error": False,
"message": 'message',
"data": serializer.data
}
return Response(custom_data)
and in views i use my custom viewset
from common.baseview import ResponseModelViewSet
class PositionViewsets(ResponseModelViewSet):
serializer_class = PositionSerializer
permission_classes = (IsAuthenticated,)
model = Position
def get_queryset(self):
return Position.objects.filter(order__user=self.request.user)
I am not sure if this is the correct way of doing it or there is some other efficient way to do it. Anyway this works for my custom apps but not for the Authentication app i used the default rest apps
'rest_framework.authtoken',
'rest_auth',
For login using username and password and get the success response as follows.
{
"key": "e642efd0b78e08b57bf34fa999f49b70a7bfe21a"
}
Instead i need this.
{
"status": "200",
"error": "False",
"data": [
{
"token":{
"key":"e642efd0b78e08b57bf34fa999f49b70a7bfe21a"
}
}
],
"message": "Login Sucess"
}
for error
{
"status": "error",
"error": "True",
"data": [
{
"email": ["Enter a valid email address."]
}
],
"message": "Login Failed"
}
After some research I found a way to do this. I had to override the default behaviour of the ModelViewSet
to output a different response.
I created a custom Response
format initially:
class ResponseInfo(object):
def __init__(self, user=None, **args):
self.response = {
"status": args.get('status', True),
"error": args.get('error', 200),
"data": args.get('data', []),
"message": args.get('message', 'success')
}
Then use this custom format in every method of the ModelViewSet
:
class ResponseModelViewSet(viewsets.ModelViewSet):
def __init__(self, **kwargs):
self.response_format = ResponseInfo().response
super(ResponseModelViewSet, self).__init__(**kwargs)
def list(self, request, *args, **kwargs):
response_data = super(ResponseModelViewSet, self).list(request, *args, **kwargs)
self.response_format["data"] = response_data.data
self.response_format["status"] = True
if not response_data.data:
self.response_format["message"] = "List empty"
return Response(self.response_format)
def create(self, request, *args, **kwargs):
response_data = super(ResponseModelViewSet, self).create(request, *args, **kwargs)
self.response_format["data"] = response_data.data
self.response_format["status"] = True
return Response(self.response_format)
def retrieve(self, request, *args, **kwargs):
response_data = super(ResponseModelViewSet, self).retrieve(request, *args, **kwargs)
self.response_format["data"] = response_data.data
self.response_format["status"] = True
if not response_data.data:
self.response_format["message"] = "Empty"
return Response(self.response_format)
def update(self, request, *args, **kwargs):
response_data = super(ResponseModelViewSet, self).update(request, *args, **kwargs)
self.response_format["data"] = response_data.data
self.response_format["status"] = True
return Response(self.response_format)
def destroy(self, request, *args, **kwargs):
response_data = super(ResponseModelViewSet, self).destroy(request, *args, **kwargs)
self.response_format["data"] = response_data.data
self.response_format["status"] = True
return Response(self.response_format)
This would be more a more robust solution, as it can be used with Generic Views hassle free.
Also, the checks in render() can be easily altered as per the needs (Eg., handling no-2XX 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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With