国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

腳本之家,腳本語言編程技術及教程分享平臺!
分類導航

Python|VBS|Ruby|Lua|perl|VBA|Golang|PowerShell|Erlang|autoit|Dos|bat|

服務器之家 - 腳本之家 - Python - Django REST framework 異常處理

Django REST framework 異常處理

2021-12-10 10:36西紅柿蛋炒飯 Python

本文將結合實例代碼,介紹Django REST framework 異常處理,文中通過示例代碼介紹的非常詳細,需要的朋友們下面隨著小編來一起學習學習吧

寫在前面

這兩天一直在思索關于 DRF 還有哪些是項目必備的而且還沒有說到的基礎性的知識。這不昨天寫到日志相關的功能就直接想到還有異常處理相關的功能,其實在之前項目中初期是沒有統一的異常捕獲手段。可能是 DRF 自帶的異常 能滿足大多數功能,也可能是比較懶,就使用比較粗暴的方式,以狀態碼 500 的方式去拋出異常,然后在日志中可以看到所有的異常信息。這么做呢,代碼其實是不夠健壯的,前端在調用的時候莫名的 500 也是不夠友好的,所以今天就補充一下異常相關的知識。

DRF異常處理

1. DRF 常見的異常

  • AuthenticationFailed/ NotAuthenticated 一般該異常狀態碼為"401 Unauthenticated",主要是沒有登錄鑒權的時候會返回,可以用在自定義登錄的時候。
  • PermissionDenied 一般用在鑒權時候使用,一般狀態碼為"403 Forbidden"。
  • ValidationError 一般狀態碼為"400 Bad Request",主要是 serializers 中對字段的校驗,比如對字段類型的校驗、字段長度的校驗以及自定義字段格式的校驗。

2. 自定義異常

這里對異常的定義主要的想法來自 ValidationError,統一異常返回的格式,方便前端統一處理類似異常。

自定義異常

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 新建 utils/custom_exception.py
 
class CustomException(Exception):
    _default_code = 400
 
    def __init__(
        self,
        message: str = "",
        status_code=status.HTTP_400_BAD_REQUEST,
        data=None,
        code: int = _default_code,
    ):
 
        self.code = code
        self.status = status_code
        self.message = message
        if data is None:
            self.data = {"detail": message}
        else:
            self.data = data
 
    def __str__(self):
        return self.message

自定義異常處理

?
1
2
3
4
5
6
7
8
9
10
11
12
# utils/custom_exception.py
from rest_framework.views import exception_handler
 
def custom_exception_handler(exc, context):
    # Call REST framework's default exception handler first,
    # to get the standard error response.
    
    # 這里對自定義的 CustomException 直接返回,保證系統其他異常不受影響
    if isinstance(exc, CustomException):
        return Response(data=exc.data, status=exc.status)
    response = exception_handler(exc, context)
    return response

配置自定義異常處理類

?
1
2
3
4
REST_FRAMEWORK = {
    # ...
    "EXCEPTION_HANDLER": "utils.custom_exception.custom_exception_handler",
}

3. 使用自定義異常

使用之前文章的接口用來測試自定義異常的處理

?
1
2
3
4
5
6
7
8
9
10
11
12
class ArticleViewSet(viewsets.ModelViewSet):
    """
    允許用戶查看或編輯的API路徑。
    """
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
 
    @action(detail=False, methods=["get"], url_name="exception", url_path="exception")
    def exception(self, request, *args, **kwargs):
        # 日志使用 demo
        logger.error("自定義異常")
        raise CustomException(data={"detail": "自定義異常"})

4. 驗證結果

?
1
2
3
4
$ curl -H 'Accept: application/json; indent=4' -u admin:admin http://127.0.0.1:8000/api/article/exception/
{
    "detail": "自定義異常"
}

異常處理進階

上面的代碼雖說是可以滿足90%的需求,但是錯誤的定義太泛泛。難以集中定義管理錯誤,與常見項目中自定義的異常比較優點就是靈活,但是隨著代碼中拋出的異常越來越多加之散落在各個角落,不利于更新維護。所以下面對修改一下代碼,對異常有統一的定義,同時也支持自定義返回HTTP狀態碼。

1. 修改自定義異常

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# utils/custom_exception.py
 
class CustomException(Exception):
    # 自定義code
    default_code = 400
    # 自定義 message
    default_message = None
 
    def __init__(
            self,
            status_code=status.HTTP_400_BAD_REQUEST,
            code: int = None,
            message: str = None,
            data=None,
    ):
        self.status = status_code
        self.code = self.default_code if code is None else code
        self.message = self.default_message if message is None else message
 
        if data is None:
            self.data = {"detail": self.message, "code": self.code}
        else:
            self.data = data
 
    def __str__(self):
        return str(self.code) + self.message

2. 自定義更多異常

?
1
2
3
4
5
6
7
8
9
10
class ExecuteError(CustomException):
    """執行出錯"""
    default_code = 500
    default_message = "執行出錯"
 
 
class UnKnowError(CustomException):
    """執行出錯"""
    default_code = 500
    default_message = "未知出錯"

3. 新增測試接口

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
class ArticleViewSet(viewsets.ModelViewSet):
    """
    允許用戶查看或編輯的API路徑。
    """
    queryset = Article.objects.all()
    serializer_class = ArticleSerializer
 
    @action(detail=False, methods=["get"], url_name="exception", url_path="exception")
    def exception(self, request, *args, **kwargs):
        # 日志使用 demo
        logger.error("自定義異常")
        raise CustomException(data={"detail": "自定義異常"})
 
    @action(detail=False, methods=["get"], url_name="unknown", url_path="unknown")
    def unknown(self, request, *args, **kwargs):
        # 日志使用 demo
        logger.error("未知錯誤")
        raise UnknownError()
 
    @action(detail=False, methods=["get"], url_name="execute", url_path="execute")
    def execute(self, request, *args, **kwargs):
        # 日志使用 demo
        logger.error("執行錯誤")
        raise ExecuteError()

4. 驗證結果

?
1
2
3
4
5
6
7
8
9
10
curl -H 'Accept: application/json; indent=4' -u admin:admin http://127.0.0.1:8000/api/article/unknown/
{
    "detail": "未知出錯",
    "code": 500
}
$ curl -H 'Accept: application/json; indent=4' -u admin:admin http://127.0.0.1:8000/api/article/execute/
{
    "detail": "執行出錯",
    "code": 500
}

總結

需要注意自定義的異常處理函數需要在處理完成自定義異常后繼續執行 rest_framework.views.exception_handler,因為這里的執行仍然需要兼容已有的異常處理;下面貼一下 DRF 有關的異常處理邏輯。

該處理函數默認處理 APIException以及 Django 內部的 Http404 PermissionDenied,其他的異常會返回 None ,會觸發 DRF 500 的錯誤。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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

參考資料

Django REST framework 異常文檔
Django 異常文檔

到此這篇關于Django REST framework 異常處理的文章就介紹到這了,更多相關Django REST framework 異常內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://juejin.cn/post/6976496971368366116

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 最新国产在线 | 亚洲aⅴ网站 | 久久国产精品久久国产精品 | 日本中文字幕网 | 亚洲男人皇宫 | 日韩有码在线播放 | 亚洲在线视频 | 亚洲视频在线免费观看 | 中文字幕一区在线 | 欧美综合区| 欧美精品亚洲精品 | 国产黄色大全 | 91精品视频导航 | 国产h片在线观看 | 在线国产视频 | 久久国产精品久久国产精品 | 精品久久久久久久中文字幕 | 国产片在线观看免费观看 | 日韩成人一级片 | 91av导航| 国产尤物| 在线国产视频 | 精品久久久久久久久久久久久久 | 久久久久久久久久久久福利 | 欧美日韩精品一区二区公司 | 日韩精品一区二区三区中文在线 | 九一精品 | 成年人免费在线看网站 | 国产在线看片 | 日韩中文字幕一区二区三区 | 香蕉久久久久久 | 99国产精品99久久久久久 | 免看一级一片 | 国产成人精品免费 | 激情五月婷婷 | 国产精品1 | 国产一区二区av在线 | 午夜成人在线视频 | 亚洲国产精品一区二区三区 | 欧美一区二区三区黄色 | 色狠狠一区 |