快速上手Django(八) -Django之 统一异常、Response处理

news2024/11/19 15:11:57

文章目录

  • 快速上手Django(八) -Django之 统一异常、Response处理
    • 一、统一Response处理
    • 二、统一异常处理
      • 1. 需求背景
      • 2. Django、drf统一异常处理
      • 3. Django、drf异常处理基础
      • 4. 纯django场景下
      • 5. 【重要】使用drf场景下,实现思路
        • 编写自定义异常处理方法
        • 在settings/dev.py文件中添加自定义异常处理模块
    • 三、工作常用总结
      • 自定义 serializers.ValidationError 的错误返回
    • 四、参考

快速上手Django(八) -Django之 统一异常、Response处理

一、统一Response处理

参考本人文章:Django 基础(3)-Django响应:rest_framework的Response、关于HttpResponse

思路:
不推荐使用HttpResponse,推荐自定义类 继承rest_framework 的 Response, 该Response继承了django原生的HttpResponse,来实现定制化需求。

直接自定义一个 MyJsonResponse 即可,我们在view中,直接return 这个类即可。

class MyJsonResponse(Response):
    def __init__(self, code=None, msg: Union[str, dict] = 'success',
                 data=None, status=None, template_name=None, headers=None,
                 exception=False, content_type=None, **kwargs):
        super().__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)

        # 改变错误提示格式
        if isinstance(msg, dict):
            for k, v in msg.items():
                for i in v:
                    msg = "%s:%s" % (k, i)

        # 自定义返回格式
        if code is None:
            code = 2000
        self.data = {'code': code, 'msg': msg, 'data': data}
        self.data.update(kwargs)
        self.template_name = template_name
        self.exception = exception
        self.content_type = content_type

        if headers:
            for name, value in headers.items():
                self[name] = value

二、统一异常处理

Django 统一异常处理
参考URL: https://cloud.tencent.com/developer/article/1912568

1. 需求背景

在项目中统一异常处理,可以防止代码中有未捕获的异常出现。

我们想让异常结果也显示为统一的返回结果对象,并且统一处理系统的异常信息,那么需要统一异常处理。

统一规范,方便前后端进行错误统一处理。同时可以更好的区分是因为网络异常,还是后端异常。

后端封装异常的好处是,如果后端异常HTTP RESP CODE是200,代表请求正确打到后端并取得了响应,如果不封装,那么如果出了异常,无法通过HTTP返回码正确区分。

当然也有人不喜欢这种后端异常都是 HTTP RESP CODE是200。其实这里还有一个非常重要的作用,就是一些异常我们要捕获出来,不要暴露给前端。 如果不喜欢的 所有后端异常都是 HTTP RESP CODE是200,这块全局处理,你也可以配置响应的 HTTP RESP CODE是 500,但是这块统一处理了,我们给前端返回的格式就统一了,这个点比较好!

这样,我们给前端返回的错误信息,就可以根据情况展示到界面上了,可以和前端沟通这种特定格式返回才可以展示到界面上~

2. Django、drf统一异常处理

Django与DRF结合的全局异常处理方案详解
参考URL: jb51.net/article/238484.htm
Django RestFramework 全局异常处理详解
参考URL: https://www.easck.com/cos/2022/0228/909945.shtml

3. Django、drf异常处理基础

Django 和 DRF(django rest framawork) 的结合在 python 后台中经常出现的组合。对于异常的全局处理,我们系统能有一个统一的解决方案,在开发环境能看到比较全的异常堆栈,而在生产环境能更好的给用户一个友好的提示

如果没有 DRF,我们只需要在 Django 中加一个中间件就可以解决全局异常的处理问题,但是 DRF 会帮我们处理一些异常并自动返回到客户端,因此我们要协调两者的异常处理策略

DRF 的异常都是继承自 APIException 这个类的,并且 DRF 跑出的异常会被 exception_handler 这个异常处理函数拦截(这个函数的位置在 /python3.7/site-packages/rest_framework/views.py中)

DRF 通过exception_handler 这个函数的文档签名我们知道,DRF 会处理所有继承自 APIException 的异常类,并且还会额外的处理 Django 内置的 Http404 和 PermissionDenied 异常,并将这些异常的处理结果返回到前端。

REST framework定义的异常:

  • APIException 所有异常的父类

APIException中默认的是 500状态码

  • ParseError 解析错误
  • AuthenticationFailed 认证失败
  • NotAuthenticated 尚未认证
  • PermissionDenied 权限决绝
  • NotFound 未找到
  • MethodNotAllowed 请求方式不支持
  • NotAcceptable 要获取的数据格式不支持
  • Throttled 超过限流次数
  • ValidationError 校验失败
    可以看到有些继承APIException 的异常类,覆写了 https状态码,如下
class ValidationError(APIException):
    status_code = status.HTTP_400_BAD_REQUEST

也就是说,很多的没有在上面列出来的异常,就需要我们在自定义异常中自己处理了

如果不再这些处理范围之内,函数会返回 None,这时候会给 Django 抛出一个 500 的服务器错误异常

Django 在 web 开发中往往会和 DRF 进行结合使用,DRF 有这自己的一套异常处理机制,我们可以对 DRF 中抛出的异常进行全局拦截,比如返回统一的 json 格式以便于前台进行处理。
但是我们同时在 Django 中使用后台 admin 管理数据的同时,不希望修改原有的异常返回。因此我们需要同时配置 Django 和 DRF 的全局异常来适应我们的需求。

4. 纯django场景下

整体思路:

  • 在 Django 项目中可以自定义中间件类 继承 django.middleware.common 下的 MiddlewareMixin 中间件类, 覆写process_exception函数。
  • setting.py 的MiddleWares中添加自定义的MiddleWare

在这里插入图片描述

process_exception(self, request, exception) 函数有两个参数,exception 是视图函数异常产生的 Exception 对象
process_exception 函数的执行顺序是按照 settings.py 中设置的中间件的顺序的倒序执行。( 如果注册的多个中间件类中包含process_exception函数的时候,调用的顺序跟注册的顺序是相反的
process_exception 函数只在视图函数中出现异常的时候才执行,它返回的值可以是 None,也可以是一个 HttpResponse 对象
如果返回 None,则继续由下一个中间件的 process_exception 方法来处理异常

5. 【重要】使用drf场景下,实现思路

第一步,自定义自己的异常处理函数
第二步,对 DRF 拦截的异常进行处理
第三步,将其他异常抛给 Django 处理

但是,感觉第三步,不是很需要,drf中定义我们自己业务异常处理,已经满足足够多的业务场景。

因此,这里我选择第一、二步骤!同时,结合自定义的异常和状态码枚举类,来统一和规范异常返回信息

编写自定义异常处理方法

在utils目录下创建exceptions.py文件,并编写自定义异常处理方法

from django.db import DatabaseError
from rest_framework.response import Response
from rest_framework.views import exception_handler
from rest_framework import status
from redis import RedisError
import logging
log = logging.getLogger("django")

def custom_exception_handler(exc, context):
    """
    自定义异常处理
    :param exc: 本次请求发生的异常信息
    :param context: 本次请求发送异常的执行上下文[ 本次请求的request对象,异常发送的时间,行号等...]
    :return: Response响应对象
    """
    response = exception_handler(exc, context)

    if response is None:
        """当response结果为None时,则当前程序运行的结果有2种可能: 
          1. 程序真的没有报错!
          2. 程序报错了,但是drf框架不识别!
        """
        view = context["view"]
        if isinstance(exc, DatabaseError) or isinstance(exc, RedisError):
            """数据库异常"""
            log.error('[%s] %s' % (view, exc))
            return Response("系统内部存储错误!",  status=status.HTTP_507_INSUFFICIENT_STORAGE)

    return response

参数为 exc、context,exc 为错误异常对象实例
context[‘view’] :视图类的对象
context[‘request’]:当前请求的对象
我们可以利用这些属性来生成日志,例如:

'ip地址为:%s的用户,访问:%s 视图类,报错了,请求地址是:%s'%(request.META.get('REMOTE_ADDR'),str(view),request.path)

在settings/dev.py文件中添加自定义异常处理模块

DRF 支持单独配置异常处理函数,因此第一步现在 setting 中指定自定义的异常处理函数的位置:

REST_FRAMEWORK = {
    # 异常处理
    'EXCEPTION_HANDLER': 'myxxx.utils.exceptions.custom_exception_handler',
}

三、工作常用总结

自定义 serializers.ValidationError 的错误返回

重写drf的ValidationError, 改变抛出异常的状态码
参考URL: https://blog.csdn.net/Waller_/article/details/108713156

在使用DRF进行反序列过程中,总是需要校验字段,然后返回错误结果。

ValidationError 中默认的状态码是 400

这个章节,推荐查看原文,代码很完整,完善!

四、参考

Django 和 DRF(Django Rest Framework) 下的全局异常处理
参考URL: https://blog.csdn.net/crown_0726/article/details/120792204
Django 统一异常处理
参考URL: https://cloud.tencent.com/developer/article/1912568

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/69806.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

高端前端彻底搞定this指向(详解)

这篇文章只告诉你三件事情,this,this,还TM的是this。 1,this在javascript中是可有可无的 大家在学习javascript的时候,肯定或多或少看到过了很多代码。其中肯定会发现this的身影。我们知道他是代表的指向,可是让人迷惑的是this的…

Scheduled定时任务异步执行

1.使用配置 我在使用SpringBoot配置定时任务的过程中,使用Scheduled配置了多个定时任务,但是在项目启动的时候每次只会启动一个定时任务,只好搜索一波,直到看到了 ThreadPoolTaskScheduler的源码,才发现默认开启的线程数是 1 Configuration public class ScheduledPoolConfi…

如何用代码实现决策树来决策要不要相亲?

前言 上一篇我们了解了什么是决策树,知道了决策树构建的过程,同时聊了构建决策树的两种算法,那么我们今天来看下如何使用代码实现决策树的构建。 数据分析整体流程 数据分析一般是以下的分析流程 1、加载数据集 首先我们构建数据,提供训…

windows10配置openvino

一、前言 gpu的常用部署我们是选择trt,那么cpu的部署呢?当然是英特尔的ov 这里要注意:我们一般是现在一台机器上利用exe(后续会说)安装完ov,那么以后在配好第一台软件配置后,以后部署到其他机器上只需要直接把dll和lib直接复制到另一台就可以运行了! 也就是说,只有…

Matplotlib学习笔记(第二章 2.11使用指南 一些简单的例子)

第二章 学习指南 本页包含更多使用Matplotlib的深入指南。它分为初级、中级和高级部分,以及涵盖特定主题的部分。 有关较短的示例,请参阅我们的示例页面。您还可以在我们的用户指南中找到外部资源和FAQ。 2.1介绍 这些教程涵盖了使用Matplotlib创建可…

P4设计实现链路监控

实验要求 在本次实验中,目的是编写一个P4程序,使主机能够监控网络中所有链路的使用情况本练习基于基本的IPv4转发练习,因此请确保在尝试此练习之前完成此练习(basic.p4)具体来说,我们将修改基本P4程序以处…

使用ChatGPT完成分类、检测、分割等计算机视觉任务(Pytorch)

前言 ChatGPT是一个由OpenAI训练的大型语言模型,其知识涵盖了很多领域。 虽然ChatGPT表示它不能用于写代码,但是万一是它太谦虚了呢? 下面的文字均为ChatGPT给出的回答。 使用ChatGPT解决图像分类任务 我们需要一个PyTorch模型&#xff0…

11-18-kafka-生产者理论

11-kafka-理论: Kafka 工作流程及文件存储机制 Kafka 工作流程 Kafka 中消息是以 topic 进行分类的,生产者生产消息,消费者消费消息,都是面向 topic的。 topic 是逻辑上的概念,而 partition 是物理上的概念&#xf…

【MySQL】MySQL数据库结构与操作

✨个人主页:bit me ✨当前专栏:MySQL数据库 ✨每日一语:自从厌倦于追寻,我已学会一觅即中,自从一股逆风袭来,我已能抗御八面来风,驾舟而行。 目 录 🌴一. 数据库介绍🌿1.…

工业物联网解决方案:地下水实时监测系统

地下水是水资源的重要组成部分,它具备水量稳定、水质好等特点,是农业灌溉、工矿和城市的重要水源之一,但同时也会出现沼泽化、地面沉降、滑坡等问题,影响当地自然环境和生活用水。 随着物联网通信技术的发展以及国家水资源管理的…

JavaScript (WebAPI)

目录 一、DOM 1. DOM树结构: 2. 重要概念 3. DOM 的工作流程 二、获取/操作元素 1. 获取 ① 获取单个元素 ② 获取所有元素 2. 操作 1. 获取/修改元素内容 3. 案例 三、新增元素 1. 创建元素节点 2. 插入节点到 DOM树 四、删除元素 一、DOM DOM 全…

Photoshop简单案例(8)——利用文字工具修改图片上文字

目录一、项目介绍二、原图上有要替换的文字2.1 方法1——利用修补工具修改2.2 方法2——利用移动工具(推荐)2.3 效果演示三、原图上没有要替换的文字一、项目介绍 本文介绍利用PhotoShop修改图片上的文字。修改下图图片中的学号。 二、原图上有要替换…

【HBU】2022秋线上作业-第五次-有关树的判断选择

判断题: 1. 一棵有124个结点的完全二叉树,其叶结点个数是确定的。 √ 高度为n的完全二叉树的结点数为2ⁿ-1 124位于64-1~128-1之间,所以这棵树的高度是7,前六层是满的有63个,第7层有124-6361个 64-613 第6层有…

使用Electron打包React项目

1、下载Electron Electron中文官网地址:https://www.electronjs.org/zh/docs/latest/ Electron下载如果单纯使用npm的话,会出现n多问题 所以建议使用国内的淘宝镜像 npm config set registry https://registry.npmmirror.com/然后下载 cnpm install -…

LeetCode 81. 搜索旋转排序数组 II

🌈🌈😄😄 欢迎来到茶色岛独家岛屿,本期将为大家揭晓LeetCode 81. 搜索旋转排序数组 II,做好准备了么,那么开始吧。 🌲🌲🐴🐴 一、题目名称 LeetC…

年后准备换工作的软件测试工程师们,你准备好了吗?

需要严肃说明的是:面试题库作为帮助大家准备面试的辅助资料,但是绝对不能作为备考唯一途径,因为面试是一个考察真实水平的,不是背会了答案就可以的,需要你透彻理解的,否则追问问题答不出来反而减分&#xf…

什么是dapp?如何在web中开发dapp?

web3 “Web3.0”是对“Web2.0”的改进,在此环境下,用户不必在不同中心化的平台创建多种身份,而是能打造一个去中心化的通用数字身份体系,通行各个平台。更像是一种概念吧。 区块链 区块链(Blockchain)是由…

54-64-k8s-集群监控-高可以用集群-交付部署

54-k8s-集群监控-高可以用集群-交付部署 k8s集群监控 1、概述 一个好的系统,主要监控以下内容 集群监控 节点资源利用率节点数运行Pods Pod监控 容器指标应用程序【程序占用多少CPU、内存】 2、监控平台 使用普罗米修斯【prometheus】 Grafana 搭建监控平台…

JS实现鼠标悬停变色

JS实现鼠标悬停变色 案例池子: JS实现鼠标悬停变色 JavaScript中的排他算法实现按钮单选 JavaScript中的localStorage JavaScript中的sessionStorage JavaScript实现网页关灯效果 JavaScript实现一段时间之后关闭广告 JavaScript实现按键快速获取输入框光标 …

第二证券|紧盯“有诺不行”隐疾 补齐上市公司高质量发展“短板”

有诺不可”的典型事例 “言而有信”是上市公司高质量开展的重要环节。近日,证监会印发的《推动提高上市公司质量三年举动计划(2022-2025)》(下称《举动计划》)提出,将着力处理管理领域杰出问题&#xff0c…