【Django】DRF自定義異常處理

冰冷的希望發表於2020-09-24

1.預設的異常處理

DRF有自己的異常捕獲機制,可以捕獲到APIException、Http404、PermissionDenied等異常
處理函式位於rest_framework.views.exception_handler,下面是它的原始碼

def exception_handler(exc, context):
	...
    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

2.自定義異常處理

因為DRF預設的捕獲異常的處理函式不能滿足專案其他的異常處理,所以我們需要自定義,即重新exception_handler()方法

新建一個py檔案,定義一個exception_handler()方法,複製DRF預設的原始碼,進行修改,先讓它預設的處理方式進行處理,處理不了的我們再使用自己的方式處理,若還處理不了,那就返回None

BooksTest/exceptions.py

def exception_handler(exc, context):
    # 處理得了返回一個響應,處理不了返回None
    
    # 1、把異常物件交給DRF的異常處理函式去處理
    response = drf_exception_handler(exc, context)
    if response:
        # response不為None,說明drf自行處理異常
        return response

    # 2、如果DRF異常處理函式無法處理,我們自行處理,例如處理除數為零的異常、資料庫錯誤的異常等
    if isinstance(exc, ZeroDivisionError):
        return Response({'errmsg': '除數不能為零'})
    if isinstance(exc, DatabaseError):
        return Response({'errmsg': '資料庫錯誤!'})

    return None

雖然 我們寫了exception_handler(),但是Django不知道,所以我們要指定使用它而不是預設的處理函式

settings.py

REST_FRAMEWORK = {
    # ......
    # 自定義異常處理函式的導包路徑
    'EXCEPTION_HANDLER': 'BooksTest.exceptions.exception_handler',
}

相關文章