Django Exception 知多少?

289 阅读4分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第3天,点击查看活动详情

相信很多人对异常是很敏感的,甚至有的人看到代码下方出现波浪线都会觉得内心不舒坦(尽管是格式问题,无关bug)。

当然,也没有人能百分百保证自己写的代码没有任何异常或者bug(反正个人嘴上都在说没问题,内心还是很忐忑的), 所以在代码里对于异常的处理也有比较多,有明知会有异常的爽快捕捉后决定是继续往下还是抛出,也有是抽大奖,真有问题 就抛出然后日志记录,方便后续排查问题的。

这一篇其实是对Django 的 Exception 进行简单的分析以及触发到的标准python异常介绍,大概是分为这几个点去简述。

  1. BaseException
  2. drf exception
  3. 自定义drf exception

1. BaseException

In Python, all exceptions must be instances of a class that derives from BaseException (在 Python 中,所有异常都必须是从 BaseException 派生的类的实例)

从上面这个定义来看,可以认为BaseException是所有异常的终极,也就是一个小异常(小弟)都是由BaseException(老大)允许后才可以成为一个有身份的异常,不然就是个渣渣。

那么其实也可以得知其实很多我们看到的,类似这个常用的小弟 try ... except Exception as e ..., 里面的Exception其实就是继承BaseException派生出来的一个比较有身份, 地位比较高的小弟,通过这个就可以捕捉到更多的小弟(异常),甚至是可能你都没有见过的。

其实既然知道了老大是BaseException,那么日常想去定义一个独特的异常,大概也知道门路了。

那么定义一个微笑异常大概类似这样子:

class SmileException(BaseException):
    def __init__(self):
        super().__init__()

    def __str__(self):
        return "Smile Error"

2. drf exception

Django 会引发一些自己的异常以及标准的 Python 异常,Django 核心异常类定义在 django.core.exceptions 中.

drf exception中也有挺多派生的异常,可以具体定位到是哪一些步骤出现问题,更利于问题的排查,具体的可以去官方文档链接中去查看,这里贴一下链接, 有需要可以去看一下:docs.djangoproject.com/zh-hans/3.2…

对于django 中使用了drf,那么drf是什么时候去检查这些异常的呢?

drf 对于请求抛异常的情况下是通过drf中handle_exception 处理,找到对应的异常处理方法,也就是views中exception_handler方法。

如果这个方法处理不了异常,则把异常抛到更高层,也就是django中去处理。 通常对于这样的restful api,我们不会在 django中增加额外的处理,只需要在DRF框架中捕获即可。

大体流程 api request -> views -> 解析过程及response数据 -> 有异常,捕捉返回到response -> 返回response -> 无异常,直接返回response

3. 自定义drf exception

因为不同异常可能response的信息内容结构不一样,所有通过第二步,其实也可以设置全局异常捕捉的内容返回。

如何自定义一个全局异常处理函数?

  1. 自定义custom_exception.py文件
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import exception_handler


def custom_exception_handler(exc, context):
    """
    先调用REST framework默认的异常处理方法获得标准错误响应对象
    :param exc: 错误原因   还可以做更详细的原因,通过判断exc信息类型
    :param context: 错误信息
    :return:
    """
    response = exception_handler(exc, context)
    if response is None:
        return Response({
            'message': 'error:{exc}'.format(exc=exc)
        }, status=status.HTTP_500_INTERNAL_SERVER_ERROR, exception=True)
    else:
        return Response({
            'message': 'error:{exc}'.format(exc=exc),
        }, status=response.status_code, exception=True)
  1. settings.py 文件配置
REST_FRAMEWORK = {
    'EXCEPTION_HANDLER': 'utils.custom_exceptions.custom_exception_handler', 
}

通过上面这两步,那么如果接口请求的时候发生异常,都会按照自定义的custom_exception_handler里面定义的内容进行返回, 也不需要再手动去处理异常输出response格式,更为的简单快捷。

结语

截止到这里,该讲的已经讲完了,也希望这些东西能给人一点点作用,当然,文章不是完美的,有缺漏有错的也可以提出来,我也能进一步学习。

最后,如果可以,点赞支持一波也行。