2

最近我开始更深入地研究 DRF,我想开始自定义通过 API 返回的错误消息以获得不正确的权限,我想包装一些额外的细节。

例如,如果没有为权限受限的端点提供身份验证凭据,API 将返回:

{
    "detail": "Authentication credentials were not provided."
}

它来自第 171 行rest_framework.exceptionshttps ://github.com/encode/django-rest-framework/blob/master/rest_framework/exceptions.py 。真的,我希望这与

{
    "success": false,
    "message": "Authentication credentials were not provided.",
    "data": null
}

所以,我假设我现在需要开始自定义我自己的异常。

我应该如何最好地做到这一点?

也许它与default_error_messages = {}序列化程序内部有一些联系......

4

2 回答 2

2

您可以覆盖 DRF 的默认异常处理程序和 JSON 解析器settings.py

REST_FRAMEWORK = {
    ...
    'EXCEPTION_HANDLER': 'helpers.exceptions.custom_exception_handler',
    'DEFAULT_RENDERER_CLASSES': [
        'helpers.renderers.JSONRenderer',
        'rest_framework.renderers.BrowsableAPIRenderer',
    ]
}

然后只需自定义如何处理异常以及如何呈现响应即可:

def custom_exception_handler(exc, context):
    # Call REST framework's default exception handler first,
    # to get the standard error response.
    response = exception_handler(exc, context)
    # Customize your exception handling here
    return response

如果您需要对响应进行任何额外的格式化,您可以使用自定义 JSON 渲染器,在我的情况下,我必须向有效负载添加“status_code”:

class JSONRenderer(BaseJsonRenderer):
    def render(self, data, accepted_media_type=None, renderer_context=None):
        """
        Render `data` into JSON, returning a bytestring.
        """
        <Base code from the original class...>

        response = renderer_context.get('response')
        if response and 200 <= response.status_code <= 299 and 'status_code' not in response.data:
            response.data = Errors.success(response.data)

        <Base code from the original class...>

Errors.success(response.data)只是将成功状态代码合并到数据的一种更简单的方法。

于 2020-02-20T13:56:27.297 回答
1

有一个装饰器解决方案可以为您的每种异常类型创建自定义响应:

# project/api/exceptions.py
from functools import wraps

from rest_framework import status


def handle_exceptions(func):
    @wraps(func)
    def wrapper(*args, **kwargs):
        try:
            return func(*args, **kwargs)
        except AuthCredentialsError as exc:
            return Response(
                {"message": exc.message},
                status=status.HTTP_405_METHOD_NOT_ALLOWED,
            )
    return wrapper


# project/api/your_code.py
from project.api.exceptions import handle_exceptions


class SomeViewSet():

    @handle_exceptions
    def create(self, request, *args, **kwargs):
        raise AuthCredentialsError("Authentication credentials were not provided")
于 2020-02-20T10:21:05.967 回答