DRF:自定义来自 API 的异常消息
DRF: Customising Exception Messages from the API
我最近开始更深入地研究 DRF,我想知道我想开始自定义通过 API 获取 return 的错误消息以获得不正确的权限,我想包装一些额外的细节。
例如,如果没有为权限受限的端点提供身份验证凭据,API returns:
{
"detail": "Authentication credentials were not provided."
}
来自 rest_framework.exceptions
的第 171 行:https://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 = {}
有一些联系...
有一个装饰器解决方案可以针对每种类型的异常创建自定义响应:
# 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")
您可以在 settings.py
:
上覆盖 DRF 的默认异常处理程序和 JSON 解析器
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)
只是一种将成功状态代码合并到数据的更简单的方法。
我最近开始更深入地研究 DRF,我想知道我想开始自定义通过 API 获取 return 的错误消息以获得不正确的权限,我想包装一些额外的细节。
例如,如果没有为权限受限的端点提供身份验证凭据,API returns:
{
"detail": "Authentication credentials were not provided."
}
来自 rest_framework.exceptions
的第 171 行:https://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 = {}
有一些联系...
有一个装饰器解决方案可以针对每种类型的异常创建自定义响应:
# 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")
您可以在 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)
只是一种将成功状态代码合并到数据的更简单的方法。