转自https://blog.csdn.net/yyy72999/article/details/84287243
这里我需要自定义返回的json的格式,主要是因为我需要返回状态码code,返回信息msg,以及原始数据data
我在工程目录下的backend app中,新建了一个文件夹utils
并创建文件
custom_json_response.py
from django.utils import six
from rest_framework.response import Response
from rest_framework.serializers import Serializer
class JsonResponse(Response):
"""
An HttpResponse that allows its data to be rendered into
arbitrary media types.
"""
def __init__(self, data=None, code=None, msg=None,
status=None,
template_name=None, headers=None,
exception=False, content_type=None):
"""
Alters the init arguments slightly.
For example, drop 'template_name', and instead use 'data'.
Setting 'renderer' and 'media_type' will typically be deferred,
For example being set automatically by the `APIView`.
"""
super(Response, self).__init__(None, status=status)
if isinstance(data, Serializer):
msg = (
'You passed a Serializer instance as data, but '
'probably meant to pass serialized `.data` or '
'`.error`. representation.'
)
raise AssertionError(msg)
self.data = {"code": code, "message": msg, "data": data}
self.template_name = template_name
self.exception = exception
self.content_type = content_type
if headers:
for name, value in six.iteritems(headers):
self[name] = value
这个类是用来包装返回rest-framework返回的json数据,可以看到它继承自rest_framework.response.Response
那么如何引用这个自定义返回呢,我们需要重写rest-framework的viewset类
custom_viewset_base.py
from rest_framework import status
from rest_framework import viewsets
from backend.utils.json_response import JsonResponse
from rest_framework import filters
from django_filters import rest_framework
class CustomViewBase(viewsets.ModelViewSet):
# pagination_class = LargeResultsSetPagination
# filter_class = ServerFilter
queryset = ''
serializer_class = ''
permission_classes = ()
filter_fields = ()
search_fields = ()
filter_backends = (rest_framework.DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter,)
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)
return JsonResponse(data=serializer.data, msg="success", code=201,
status=status.HTTP_201_CREATED, headers=headers)
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)
return JsonResponse(data=serializer.data, code=200, msg="success", status=status.HTTP_200_OK)
def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
serializer = self.get_serializer(instance)
return JsonResponse(data=serializer.data, code=200, msg="success", status=status.HTTP_200_OK)
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 = {}
return JsonResponse(data=serializer.data, msg="success", code=200, status=status.HTTP_200_OK)
def destroy(self, request, *args, **kwargs):
instance = self.get_object()
self.perform_destroy(instance)
return JsonResponse(data=[], code=204, msg="delete resource success", status=status.HTTP_204_NO_CONTENT)
可以看到每一个方法都返回了刚才定义的JsonResponse
分页器也需要重新定义
custom_pagination.py
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination
from collections import OrderedDict
from rest_framework.response import Response
class LargeResultsSetPagination(LimitOffsetPagination):
page_size = 10
page_size_query_param = 'page_size'
max_page_size = 10000
def get_paginated_response(self, data):
code = 200
msg = 'success'
if not data:
code = 404
msg = "Data Not Found"
return Response(OrderedDict([
('code', code),
('msg', msg),
('count', self.count),
('next', self.get_next_link()),
('previous', self.get_previous_link()),
('data', data),
]))
并自定错误处理
custom_exception.py
from rest_framework.views import exception_handler
def custom_exception_handler(exc, context):
# Call REST framework's default exception handler first,
# to get the standard error response.
response = exception_handler(exc, context)
# Now add the HTTP status code to the response.
if response is not None:
print(response.data)
print(response)
response.data.clear()
response.data['code'] = response.status_code
response.data['data'] = []
if response.status_code == 404:
try:
response.data['message'] = response.data.pop('detail')
response.data['message'] = "Not found"
except KeyError:
response.data['message'] = "Not found"
if response.status_code == 400:
response.data['message'] = 'Input error'
elif response.status_code == 401:
response.data['message'] = "Auth failed"
elif response.status_code >= 500:
response.data['message'] = "Internal service errors"
elif response.status_code == 403:
response.data['message'] = "Access denied"
elif response.status_code == 405:
response.data['message'] = 'Request method error'
response.code = response.status_code
response.status_code = 200
return response
上述的分页器和错误处理函数,需要在setting.py中引用
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'backend.utils.custom_pagination.LargeResultsSetPagination',
'PAGE_SIZE': 10,
'EXCEPTION_HANDLER': 'backend.utils.custom_exception_handler.custom_exception_handler',
}
最后一步,我们之前写好的View中的类,不再继承自rest_framework.viewsets,而是继承自我们自己定义的custom_viewset_base
如,user.py
from django.contrib.auth.models import User
from backend.utils.viewset_base import CustomViewBase
from backend.serializers.user import UserSerializer
class UserViewSet(CustomViewBase):
"""
API endpoint that allows users to be viewed or edited.
"""
queryset = User.objects.all().order_by('-date_joined')
serializer_class = UserSerializer
运行后,可以看到json返回增加了code字段和message字段
另:为了增强的filter,可以安装'django_filters'并在django中引用
INSTALLED_APPS = [
...
'django_filters',
]