溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點(diǎn)擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

python中怎么通過Django捕獲所有異常的處理

發(fā)布時(shí)間:2021-09-30 09:11:14 來源:億速云 閱讀:240 作者:小新 欄目:開發(fā)技術(shù)

這篇文章主要為大家展示了“python中怎么通過Django捕獲所有異常的處理”,內(nèi)容簡而易懂,條理清晰,希望能夠幫助大家解決疑惑,下面讓小編帶領(lǐng)大家一起研究并學(xué)習(xí)一下“python中怎么通過Django捕獲所有異常的處理”這篇文章吧。

    概述

    在項(xiàng)目中統(tǒng)一異常處理,可以防止代碼中有未捕獲的異常出現(xiàn)。本文介紹如何在 Django 項(xiàng)目中進(jìn)行統(tǒng)一異常的處理,再結(jié)合狀態(tài)碼枚舉類對項(xiàng)目異常信息進(jìn)行日志記錄。

    Django 統(tǒng)一異常處理

    Django 項(xiàng)目中可以自定義 中間件類 繼承 django.middleware.common 下的 MiddlewareMixin 中間件類,重寫 process_exception 方法的異常處理邏輯,然后在項(xiàng)目配置下的 中間件中注冊 即可進(jìn)行全局異常處理。

    我是在項(xiàng)目自定義的 utils 包下 middlewares.py 模塊中下進(jìn)行中間件的編寫。

    # middlewares.py
    
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    # @Author: Hui
    # @Desc: { 項(xiàng)目中間件模塊 }
    # @Date: 2021/09/24 8:18
    from django.middleware.common import MiddlewareMixin
    
    
    
    class ExceptionMiddleware(MiddlewareMixin):
        """統(tǒng)一異常處理中間件"""
    
        def process_exception(self, request, exception):
            """
            統(tǒng)一異常處理
            :param request: 請求對象
            :param exception: 異常對象
            :return:
            """
            # 異常處理
            print(exception)
            return None

    這里暫時(shí)先簡單進(jìn)行異常輸出,來模擬異常處理。最后不要忘記 在配置文件中注冊中間件。django 項(xiàng)目默認(rèn)的配置文件是 settings.py 我這里只是把配置文件單獨(dú)放到了 settings 包下然后改了文件名。

    python中怎么通過Django捕獲所有異常的處理

    process_exception 方法介紹

    process_exception 方法只有在視圖函數(shù)中出現(xiàn)異常了才執(zhí)行。該方法的返回值可以是一個(gè) None 也可以是一個(gè) HttpResponse 對象。

    • 返回值是 None,頁面會(huì)報(bào) 500 狀態(tài)碼錯(cuò)誤,視圖函數(shù)不會(huì)執(zhí)行。

    • 返回值是 HttpResponse 對象,則是對應(yīng)的響應(yīng)信息,頁面不會(huì)報(bào)錯(cuò)。

    中間件中的方法

    方法作用
    process_request(self,request)在視圖函數(shù)之前執(zhí)行
    process_view(self, request, view_func, view_args, view_kwargs)視圖函數(shù)之前,process_request 方法之后執(zhí)行
    process_exception(self, request, exception)視圖函數(shù)中出現(xiàn)異常了才執(zhí)行
    process_response(self, request, response)視圖函數(shù)之后執(zhí)行

    下面一圖就能比較好的呈現(xiàn) django 整個(gè)處理流程邏輯

    python中怎么通過Django捕獲所有異常的處理

    更多的中間件細(xì)節(jié)可以去 Django 官方文檔 進(jìn)行了解。

    統(tǒng)一異常處理具體設(shè)計(jì)

    結(jié)合自定義的異常和狀態(tài)碼枚舉類,進(jìn)行異常日志信息和業(yè)務(wù)邏輯的處理。

    自定義異常模塊

    # exceptions.py
    
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    # @Author: Hui
    # @Desc: { 項(xiàng)目異常模塊 }
    # @Date: 2021/09/24 8:14
    
    class CommonException(Exception):
        """公共異常類"""
    
        def __init__(self, enum_cls):
            self.code = enum_cls.code
            self.errmsg = enum_cls.errmsg
            self.enum_cls = enum_cls	# 狀態(tài)碼枚舉類
            super().__init__()
    
    
    class BusinessException(CommonException):
        """業(yè)務(wù)異常類"""
        pass
    
    
    class APIException(CommonException):
        """接口異常類"""
        pass

    自定義狀態(tài)碼枚舉類

    # enums.py
    
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    # @Author: Hui
    # @Desc: { 項(xiàng)目枚舉類模塊 }
    # @Date: 2021/09/23 23:37
    
    from enum import Enum
    
    
    class StatusCodeEnum(Enum):
        """狀態(tài)碼枚舉類"""
    
        OK = (0, '成功')
        ERROR = (-1, '錯(cuò)誤')
        SERVER_ERR = (500, '服務(wù)器異常')
    
        IMAGE_CODE_ERR = (4001, '圖形驗(yàn)證碼錯(cuò)誤')
        THROTTLING_ERR = (4002, '訪問過于頻繁')
        NECESSARY_PARAM_ERR = (4003, '缺少必傳參數(shù)')
        USER_ERR = (4004, '用戶名錯(cuò)誤')
        PWD_ERR = (4005, '密碼錯(cuò)誤')
        CPWD_ERR = (4006, '密碼不一致')
        MOBILE_ERR = (4007, '手機(jī)號錯(cuò)誤')
        SMS_CODE_ERR = (4008, '短信驗(yàn)證碼有誤')
        ALLOW_ERR = (4009, '未勾選協(xié)議')
        SESSION_ERR = (4010, '用戶未登錄')
        REGISTER_FAILED_ERR = (4011, '注冊失敗')
    
        DB_ERR = (5000, '數(shù)據(jù)庫錯(cuò)誤')
        EMAIL_ERR = (5001, '郵箱錯(cuò)誤')
        TEL_ERR = (5002, '固定電話錯(cuò)誤')
        NODATA_ERR = (5003, '無數(shù)據(jù)')
        NEW_PWD_ERR = (5004, '新密碼錯(cuò)誤')
        OPENID_ERR = (5005, '無效的openid')
        PARAM_ERR = (5006, '參數(shù)錯(cuò)誤')
        STOCK_ERR = (5007, '庫存不足')
    
        @property
        def code(self):
            """獲取狀態(tài)碼"""
            return self.value[0]
    
        @property
        def errmsg(self):
            """獲取狀態(tài)碼信息"""
            return self.value[1]
    • 自定義的異常類用于區(qū)分系統(tǒng)異常和業(yè)務(wù)來進(jìn)行單獨(dú)處理。

    • 狀態(tài)碼枚舉則是用來記錄對應(yīng)的異常信息。

    狀態(tài)碼枚舉類的設(shè)計(jì)可以查閱 巧用Python 枚舉類設(shè)計(jì)狀態(tài)碼信息

    響應(yīng)信息統(tǒng)一結(jié)果的封裝

    統(tǒng)一前后端交互數(shù)據(jù)和異常信息結(jié)果。

    # result.py
    
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    # @Author: Hui
    # @Desc: { 項(xiàng)目信息返回結(jié)果模塊 }
    # @Date: 2021/09/23 22:10
    from .enums import StatusCodeEnum
    
    
    class R(object):
        """
        統(tǒng)一項(xiàng)目信息返回結(jié)果類
        """
    
        def __init__(self):
            self.code = None
            self.errmsg = None
            self._data = dict()
    
        @staticmethod
        def ok():
            """
            組織成功響應(yīng)信息
            :return:
            """
            r = R()
            r.code = StatusCodeEnum.OK.code
            r.errmsg = StatusCodeEnum.OK.errmsg
            return r
    
        @staticmethod
        def error():
            """
            組織錯(cuò)誤響應(yīng)信息
            :return:
            """
            r = R()
            r.code = StatusCodeEnum.ERROR.code
            r.errmsg = StatusCodeEnum.ERROR.errmsg
            return r
    
        @staticmethod
        def server_error():
            """
            組織服務(wù)器錯(cuò)誤信息
            :return:
            """
            r = R()
            r.code = StatusCodeEnum.SERVER_ERR.code
            r.errmsg = StatusCodeEnum.SERVER_ERR.errmsg
            return r
    
        @staticmethod
        def set_result(enum):
            """
            組織對應(yīng)枚舉類的響應(yīng)信息
            :param enum: 狀態(tài)枚舉類
            :return:
            """
            r = R()
            r.code = enum.code
            r.errmsg = enum.errmsg
            return r
    
        def data(self, key=None, obj=None):
            """統(tǒng)一后端返回的數(shù)據(jù)"""
    
            if key:
                self._data[key] = obj
    
            context = {
                'code': self.code,
                'errmsg': self.errmsg,
                'data': self._data
            }
            return context

    完善統(tǒng)一異常處理邏輯

    # middlewares.py
    
    #!/usr/bin/python3
    # -*- coding: utf-8 -*-
    # @Author: Hui
    # @Desc: { 項(xiàng)目中間件模塊 }
    # @Date: 2021/09/24 8:18
    import logging
    
    from django.db import DatabaseError
    from django.http.response import JsonResponse
    from django.http import HttpResponseServerError
    from django.middleware.common import MiddlewareMixin
    
    from meiduo_mall.utils.result import R
    from meiduo_mall.utils.enums import StatusCodeEnum
    from meiduo_mall.utils.exceptions import BusinessException
    
    logger = logging.getLogger('django')
    
    
    class ExceptionMiddleware(MiddlewareMixin):
        """統(tǒng)一異常處理中間件"""
    
        def process_exception(self, request, exception):
            """
            統(tǒng)一異常處理
            :param request: 請求對象
            :param exception: 異常對象
            :return:
            """
            if isinstance(exception, BusinessException):
                # 業(yè)務(wù)異常處理
                data = R.set_result(exception.enum_cls).data()
                return JsonResponse(data)
    
            elif isinstance(exception, DatabaseError):
                # 數(shù)據(jù)庫異常
                r = R.set_result(StatusCodeEnum.DB_ERR)
                logger.error(r.data(), exc_info=True)
                return HttpResponseServerError(StatusCodeEnum.SERVER_ERR.errmsg)
    
            elif isinstance(exception, Exception):
                # 服務(wù)器異常處理
                r = R.server_error()
                logger.error(r.data(), exc_info=True)
                return HttpResponseServerError(r.errmsg)
            
            return None

    應(yīng)用場景

    注冊校驗(yàn)

    讓我們來看一段注冊校驗(yàn)功能業(yè)務(wù)邏輯

    	def verify_params(self, request):
            """
            校驗(yàn)注冊信息
            :param request: 注冊請求對象
            :return: response_ret
            """
            # 接受參數(shù)
            self.username = request.POST.get('username')
            self.password = request.POST.get('password')
            self.confirm_pwd = request.POST.get('confirm_pwd')
            self.mobile = request.POST.get('mobile')
            self.allow = request.POST.get('allow')   
    
            if not all(all_args):
                # raise BusinessException(StatusCodeEnum.PARAM_ERR)
                response_ret = http.HttpResponseForbidden('參數(shù)錯(cuò)誤')
                return response_ret
    
            # 用戶名 5-20個(gè)字符
            if not re.match(r'^[a-zA-Z0-9_]{5,20}', self.username):
                response_ret = http.HttpResponseForbidden('用戶名不規(guī)范')
                return response_ret
    
            # 密碼 8-20個(gè)字符
            if not re.match(r'^[a-zA-Z0-9]{8,20}', self.password):
                response_ret = http.HttpResponseForbidden('密碼不規(guī)范')
                return response_ret
    
            # 兩次密碼一致性
            if self.password != self.confirm_pwd:
                response_ret = http.HttpResponseForbidden('兩次密碼不一致')
                return response_ret
    
            # 手機(jī)號合法性
            if not re.match(r'^1[3-9]\d{9}$', self.mobile):
                response_ret = http.HttpResponseForbidden('手機(jī)號碼不合法')
                return response_ret
    
            # 是否勾選用戶協(xié)議
            if self.allow != 'on':
                response_ret = http.HttpResponseForbidden('請勾選用戶協(xié)議')
                return response_ret
    
            return response_ret

    通過拋異常和設(shè)置狀態(tài)碼枚舉來處理

    def verify_params(self, request):
            """
            校驗(yàn)注冊信息
            :param request: 注冊請求對象
            :return: response_ret
            """
            # 接受參數(shù)
            self.username = request.POST.get('username')
            self.password = request.POST.get('password')
            self.confirm_pwd = request.POST.get('confirm_pwd')
            self.mobile = request.POST.get('mobile')
            self.allow = request.POST.get('allow')
    
            # 校驗(yàn)參數(shù)
            all_args = [self.username, self.password, self.confirm_pwd, self.mobile, self.allow]
            if not all(all_args):
                raise BusinessException(StatusCodeEnum.PARAM_ERR)
    
            # 用戶名 5-20個(gè)字符
            if not re.match(r'^[a-zA-Z0-9_]{5,20}', self.username):
                raise BusinessException(StatusCodeEnum.USER_ERR)
    
            # 密碼 8-20個(gè)字符
            if not re.match(r'^[a-zA-Z0-9]{8,20}', self.password):
                raise BusinessException(StatusCodeEnum.PWD_ERR)
    
            # 兩次密碼一致性
            if self.password != self.confirm_pwd:
                raise BusinessException(StatusCodeEnum.CPWD_ERR)
    
            # 手機(jī)號合法性
            if not re.match(r'^1[3-9]\d{9}$', self.mobile):
                raise BusinessException(StatusCodeEnum.MOBILE_ERR)
    
            # 是否勾選用戶協(xié)議
            if self.allow != 'on':
                raise BusinessException(StatusCodeEnum.ALLOW_ERR)

    減少 try ... except ... 代碼塊

    例如在對數(shù)據(jù)庫進(jìn)行操作時(shí),為了防止數(shù)據(jù)庫發(fā)生了意外的異常導(dǎo)致系統(tǒng)崩潰,通常加上 try ... except ...來記錄異常信息。然而配置了全局異常處理,則可以不用管理。

    # 創(chuàng)建用戶
    try:
        user = User.objects.create_user(
            username=self.username,
            password=self.password,
            mobile=self.mobile,
        )
    except DatabaseError as e:
        logger.error(e)
        
        
    # 有了全局的異常處理
    user = User.objects.create_user(
            username=self.username,
            password=self.password,
            mobile=self.mobile,
        )

    注意:如果需要通過異常捕獲來處理一些業(yè)務(wù)信息,則不可避免,如事務(wù)回滾等

    以上是“python中怎么通過Django捕獲所有異常的處理”這篇文章的所有內(nèi)容,感謝各位的閱讀!相信大家都有了一定的了解,希望分享的內(nèi)容對大家有所幫助,如果還想學(xué)習(xí)更多知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

    向AI問一下細(xì)節(jié)

    免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

    AI