情景分析:
在以前的项目中,我们每处理一次数据库操作,就要使用try except
来捕获数据库异常并且记录日志,这个异常不是数据库语法的异常,而是数据库的连接之类的异常
有两个特殊情况需要特殊处理使用try except
:
①查询的数据不存在②增加的数据已经存在
其他的普通异常如果没有try except
,那么会交给APIView
来处理,任何APIException
异常都会被它捕获到,并且处理成合适的响应信息,返回给from rest_framework.views import exception_handler
这个包里面的response = exception_handler(exc, context)
来处理。
包括视图扩展类(CreateModelMixin)的源码里面也会有serializer.is_valid(raise_exception=True)
来检验数据,它也没有try except
来处理异常,就会把异常也往上抛给exception_handler
处理;
反序列化的校验字段也会抛出异常raise serializers.ValidationError
,这个异常也是抛给exception_handler
来处理
但是exception_handler
默认不会处理数据库的异常,所以我们就重写该方法补充该功能。
新建utils/exceptions.py
from rest_framework.views import exception_handler as drf_exception_handler
import logging
from rest_framework.response import Response
from rest_framework import status
#所有的数据库异常都是这两个异常的儿子或孙子,导入他俩就行
from django.db import DatabaseError
from redis.exceptions import RedisError
# 获取在配置文件中定义的logger,用来记录日志
logger = logging.getLogger('django')
def exception_handler(exc, context):
"""
自定义异常处理
:param exc: 别的地方抛的异常就会传给exc
:param context: 字典形式。抛出异常的上下文(即抛出异常的出处;即抛出异常的视图)
:return: Response响应对象
"""
# 调用drf框架原生的异常处理方法,把异常和异常出处交给他处理,如果是序列化器异常就直接处理,处理之后就直接返回
response = drf_exception_handler(exc, context)
#如果响应为空表示不是序列化器异常,补充数据库异常
if response is None:
view = context['view']
if isinstance(exc, DatabaseError) or isinstance(exc, RedisError):
# 数据库异常
logger.error('[%s] %s' % (view, exc))
response = Response({'message': '服务器内部错误'}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
return response