核心结论:在DRF视图中,抛出DRF的异常,DRF框架会自行捕获并构建响应返回!
思考:如果我想让drf框架,自行捕获非DRF异常,该怎么办呢?
异常捕获处理流程图示:
(1)、在DRF视图的处理过程中,由哪个函数处理异常的?
由from rest_framework.views import exception_handler
异常处理函数处理具体异常并构建响应,具体定义如下:
- 功能:处理捕获的异常
exc
:捕获到的异常对象isinstance
:用来判断一个对象的变量类型- 返回值:如果可以处理则返回响应对象,如果无法处理则返回None
# 该函数是DRF用来处理异常的函数
def exception_handler(exc, context):
"""
Returns the response that should be used for any given exception.
By default we handle the REST framework `APIException`, and also
Django's built-in `Http404` and `PermissionDenied` exceptions.
Any unhandled exceptions may return `None`, which will cause a 500 error
to be raised.
"""
if isinstance(exc, Http404):
exc = exceptions.NotFound()
elif isinstance(exc, PermissionDenied):
exc = exceptions.PermissionDenied()
if isinstance(exc, exceptions.APIException):
headers = {}
if getattr(exc, 'auth_header', None):
headers['WWW-Authenticate'] = exc.auth_header
if getattr(exc, 'wait', None):
headers['Retry-After'] = '%d' % exc.wait
if isinstance(exc.detail, (list, dict)):
data = exc.detail
else:
data = {'detail': exc.detail}
set_rollback()
return Response(data, status=exc.status_code, headers=headers)
return None
总结上述DRF框架默认使用的异常处理函数,我们发现它只能处理APIException
、Http404
和PermissionDenied
异常;除此以外的异常它无法处理。如下图,当异常为类型为ZeroDivisionError
时,就会调用Django原生的异常处理函数进行抛出异常信息。
(2)、如果该函数无法处理非DRF异常,我们需要补充逻辑?
原则上我们不能直接修改源码来补充逻辑,而是通过自定义一个异常处理函数来实现;
新建BooksTest/exceptions.py
文件,并自定义异常处理函数如下:
"""
自定义异常处理函数
"""
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework.response import Response
from django.db import DatabaseError
# 该函数是DRF用来处理异常的函数
def exception_handler(exc, context):
# 参数:exc捕获的异常对象
# 处理得了返回一个响应,处理不了返回None
# 1、把异常对象交给DRF的异常处理函数去处理
response = drf_exception_handler(exc, context)
if response:
# response不为None,说明drf自行处理异常
return response
# 2、如果DRF异常处理函数无法处理,我们自行处理
if isinstance(exc, ZeroDivisionError):
return Response({'errmsg': '除数不能为零'})
if isinstance(exc, DatabaseError):
return Response({'errmsg': '数据库错误!'})
return None
在配置文件中指定DRF的异常处理函数为我们自定义的函数:
REST_FRAMEWORK = {
# ......
# 自定义异常处理函数的导包路径
'EXCEPTION_HANDLER': 'books_test.exceptions.exception_handler',
}
- 再测试异常类型为
ZeroDivisionError
时,就会调用自定义的重写的DRF的异常处理函数: