import traceback from logging import getLogger from django.core.exceptions import PermissionDenied, ObjectDoesNotExist as DJObjectDoesNotExist from django.db.models.deletion import ProtectedError from django.http import Http404 from django.utils.translation import gettext from django.conf import settings from rest_framework import exceptions from rest_framework.response import Response from rest_framework.views import set_rollback from common.exceptions import JMSObjectDoesNotExist, ReferencedByOthers logger = getLogger('drf_exception') unexpected_exception_logger = getLogger('unexpected_exception') def extract_object_name(exc, index=0): """ `index` 是从 0 开始数的, 比如: `No User matches the given query.` 提取 `User`,`index=1` """ if exc.args: (msg, *others) = exc.args else: return gettext('Object') return gettext(msg.split(sep=' ', maxsplit=index + 1)[index]) def common_exception_handler(exc, context): if settings.DEBUG_DEV: logger.exception('Print traceback exception for Debug') traceback.print_exc() if isinstance(exc, Http404): exc = JMSObjectDoesNotExist(object_name=extract_object_name(exc, 1)) elif isinstance(exc, PermissionDenied): exc = exceptions.PermissionDenied() elif isinstance(exc, DJObjectDoesNotExist): exc = JMSObjectDoesNotExist(object_name=extract_object_name(exc, 0)) elif isinstance(exc, ProtectedError): exc = ReferencedByOthers() 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, str) and isinstance(exc.get_codes(), str): data = {'detail': exc.detail, 'code': exc.get_codes()} else: data = exc.detail set_rollback() return Response(data, status=exc.status_code, headers=headers) else: unexpected_exception_logger.exception('') return None