Title(EN): Django REST Framework Learning Notes (5): the exceptions module
Author: dog2
基本信息
异常处理
DRF异常处理
所有经过drf的APIView
视图类产生的异常,都可以提供异常处理方案
drf默认提供了异常处理方案rest_framework.views.exception_handler
,但是处理范围有限
drf提供的处理方案两种,处理了返回异常现象,没处理返回None(后续就是服务器抛异常给前台)
通常出于一些原因我们需要自定义异常处理,而非使用DRF的默认异常。
基于DRF自定义异常处理
自定义异常处理的常见应用场景如下:
解决drf没有处理的异常
让前台得到合理的异常信息返回、隐藏异常细节而返回通用异常信息
后台记录异常具体信息、如将异常细节写入日志以供审计等
源码分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 response = self.handle_exception(exc) exception_handler = self.get_exception_handler() return self.settings.EXCEPTION_HANDLERsettings = api_settings 'EXCEPTION_HANDLER' : 'rest_framework.views.exception_handler' response = exception_handler(exc, context)
从dispatch中的handle_exception
进入,get_exception_handler()
获得处理异常方法exception_handler()
,在这里也可以自定义异常方法。执行exception_handler()
获取异常处理的结果。
用法示例
自定义全局配置
这是视频教程里的做法,它对于所有视图都采用自己定制的异常处理函数。
在项目的settings.py
中
1 2 3 4 5 REST_FRAMEWORK = { 'EXCEPTION_HANDLER' : 'api.exception.exception_handler' , }
创建自定义异常处理函数,函数内部逻辑一般为
先将异常处理交给rest_framework.views
的exception_handler
去处理
判断处理的结果(返回值)response
,有值代表drf已经处理了,None
代表drf处理不了的异常,需要自定义去处理
api应用下创建处理异常文件exception.py
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 from rest_framework.views import exception_handler as drf_exception_handler from rest_framework.views import Responsefrom rest_framework import statusdef exception_handler (exc, context) : response = drf_exception_handler(exc, context) if response is None : print('%s - %s - %s' % (context['view' ], context['request' ].method, exc)) return Response({ 'detail' : 'global customized exception: internal server error' }, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True ) return response
自定义局部配置
这是我拓展的方法,它可以针对某个特定的视图类,定制不同于全局定制异常的特有处理方式。
根据前面的源码分析中可以知道,要为视图类单独定制异常处理函数,可以这样做:
在继承APIView
编写视图类时,重写父类的get_exception_handler
函数,让异常处理函数指向自定义的异常处理函数。
在视图类中加入定制的异常处理函数。
示例代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 from django.views.decorators.csrf import csrf_exemptfrom django.utils.decorators import method_decoratorfrom rest_framework.views import exception_handler as drf_exception_handlerfrom rest_framework.views import Responsefrom rest_framework import status@method_decorator(csrf_exempt, name='dispatch') class LocalExceptionView (APIView) : def post (self, request, *args, **kwargs) : print(request.query_params) print(request.data) print(request.not_exists) return Response('post ok' ) def get_exception_handler (self) : return self.exception_handler def exception_handler (self, exc, context) : response = drf_exception_handler(exc, context) if response is None : print('%s - %s - %s' % (context['view' ], context['request' ].method, exc)) return Response({ 'detail' : 'local customized exception: internal server error' }, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True ) return response
测试demo
测试代码在这里:no5_drf_exception
其中包含: