REST framework提供了異常處理,我們可以自定義異常處理函數。
官方文檔
https://www.django-rest-framework.org/api-guide/exceptions/
在配置文件中配置日志
setting.py
LOGGING = { 'version': 1, 'disable_existing_loggers': False, # 是否禁用已經存在的日志器 'formatters': { # 日志信息顯示的格式 'verbose': { 'format': '%(levelname)s %(asctime)s %(module)s %(lineno)d %(message)s' }, 'simple': { 'format': '%(levelname)s %(module)s %(lineno)d %(message)s' }, }, 'filters': { # 對日志進行過濾 'require_debug_true': { # django在debug模式下才輸出日志 '()': 'django.utils.log.RequireDebugTrue', }, }, 'handlers': { # 日志處理方法 'console': { # 向終端中輸出日志 'level': 'INFO', 'filters': ['require_debug_true'], 'class': 'logging.StreamHandler', 'formatter': 'simple' }, 'file': { # 向文件中輸出日志 'level': 'INFO', 'class': 'logging.handlers.RotatingFileHandler', 'filename': os.path.join(BASE_DIR, "logs/meiduo.log"), # 日志文件的位置 'maxBytes': 300 * 1024 * 1024, 'backupCount': 10, 'formatter': 'verbose' }, }, 'loggers': { # 日志器 'django': { # 定義了一個名為django的日志器 'handlers': ['console', 'file'], # 可以同時向終端與文件中輸出日志 'propagate': True, # 是否繼續傳遞日志信息 'level': 'INFO', # 日志器接收的最低日志級別 }, } }
DRFDemo/utils/exceptions.py
from rest_framework.views import exception_handler def custom_exception_handler(exc, context): # 先調用REST framework默認的異常處理方法獲得標准錯誤響應對象 response = exception_handler(exc, context) # 在此處補充自定義的異常處理 if response is not None: response.data['status_code'] = response.status_code return response
在配置文件中聲明自定義的異常處理
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'DRFDemo.utils.custom_exception_handler' }
如果未聲明,會采用默認的方式,如下
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'exceptions.custom_exception_handler' }
例如:
補充上處理關於數據庫的異常
from django.db import DatabaseError 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默認的異常處理方法獲得標准錯誤響應對象 response = exception_handler(exc, context) # 在此處補充自定義的異常處理 if response is None: view = context['view'] if isinstance(exc, DatabaseError): print('[%s]: %s' % (view, exc)) response = Response({'detail': '服務器內部錯誤'}, status=status.HTTP_507_INSUFFICIENT_STORAGE) return response
完整代碼如下

from rest_framework.views import exception_handler as drf_exception_handler import logging from django.db import DatabaseError from redis.exceptions import RedisError from rest_framework.response import Response from rest_framework import status # 獲取在配置文件中定義的logger,用來記錄日志 logger = logging.getLogger('django') def exception_handler(exc, context): """ 自定義異常處理 :param exc: 異常 :param context: 拋出異常的上下文 :return: Response響應對象 """ # 調用drf框架原生的異常處理方法 response = drf_exception_handler(exc, context) if response is None: view = context['view'] if isinstance(exc, DatabaseError) or isinstance(exc, RedisError): # 數據庫異常 logger.error('[%s] %s' % (view, exc)) response = Response({'message': '服務器內部錯誤'}, status=status.HTTP_507_INSUFFICIENT_STORAGE) return response
代碼中模擬一個異常:
from django.db import DatabaseError class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet): queryset = BookInfo.objects.all() serializer_class = BookInfoModelSerializer # authentication_classes = (SessionAuthentication, BasicAuthentication) # permission_classes = (IsAuthenticated,) filter_fields = ("btitle", "bread") # pagination_class = LargeResultsSetPagination pagination_class = LimitOffsetPagination def get_permissions(self): if action == "get": return [IsAuthenticated()] else: return [AllowAny()] @action(methods=["GET"], detail=False) def latest(self, request): raise DatabaseError() book = BookInfo.objects.latest("id") serializer = self.get_serializer(book) return Response(serializer.data)
訪問:
REST framework定義的異常
APIException 所有異常的父類
ParseError 解析錯誤
AuthenticationFailed 認證失敗
NotAuthenticated 尚未認證
PermissionDenied 權限決絕
NotFound 未找到
MethodNotAllowed 請求方式不支持
NotAcceptable 要獲取的數據格式不支持
Throttled 超過限流次數
ValidationError 校驗失敗
自定義一個捕獲數據庫查詢不到的異常
import logging from django.core.exceptions import ObjectDoesNotExist from rest_framework.exceptions import NotFound from rest_framework.views import exception_handler as old_exception_handler logger = logging.getLogger(__name__) def exception_handler(exc, context): logger.exception('Uncaught Exception') if isinstance(exc, ObjectDoesNotExist): exc = NotFound() return old_exception_handler( exc, context )