REST 框架提供了几种即用的身份验证方案,并且支持实现自定义认证。
我们需要在 setting.py 文件中设置 DEFAULT_AUTHENTICATION_CLASSES 全局默认身份验证方案。例如。
REST_FRAMEWORK = {'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework.authentication.BasicAuthentication','rest_framework.authentication.SessionAuthentication',]
}
还可以基于每个视图或每个视图集设置 permission_classes ,且视图中定义的认证方案会高于 DEFAULT_AUTHENTICATION_CLASSES 全局配置 。
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIViewclass ExampleView(APIView):authentication_classes = [SessionAuthentication, BasicAuthentication]permission_classes = [IsAuthenticated]def get(self, request, format=None):content = {'user': str(request.user), # `django.contrib.auth.User` instance.'auth': str(request.auth), # None}return Response(content)
或者我们也可以使用装饰器 @api_view 结合函数视图一起使用。
@api_view(['GET'])
@authentication_classes([SessionAuthentication, BasicAuthentication])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):content = {'user': str(request.user), # `django.contrib.auth.User` instance.'auth': str(request.auth), # None}return Response(content)
认证失败通常会有两种响应:
权限控制可以限制用于对于视图的访问和对于具体数据对象的访问。
可以使用该设置全局设置默认 DEFAULT_PERMISSION_CLASSES 权限策略。例如
REST_FRAMEWORK = {'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticated',]
}
如果配置文件中未指明,则设置默认为允许无限制访问
'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.AllowAny',
]
AllowAny 允许所有用户IsAuthenticated 仅通过认证的用户IsAdminUser 仅管理员用户IsAuthenticatedOrReadOnly 认证的用户可以完全操作,否则只能 Get 读取还可以基于每个视图或者每个视图集设置身份验证策略,使用基于 APIView 类的视图。
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIViewclass ExampleView(APIView):permission_classes = [IsAuthenticated]def get(self, request, format=None):content = {'status': 'request was permitted'}return Response(content)
或者 可以使用 api_view 装饰器与基于函数的视图一起使用。
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):content = {'status': 'request was permitted'}return Response(content)
注意:类属性或装饰器设置新的权限类时,他的优先级会高于 setting.py 文件中的配置。
如果他们继承自 rest_framework.permissions.BasePermission ,IsAuthenticatedOrReadOnly,则可以使用标准Python 按位运算符组合权限。
from rest_framework.permissions import BasePermission, IsAuthenticated, SAFE_METHODS
from rest_framework.response import Response
from rest_framework.views import APIViewclass ReadOnly(BasePermission):def has_permission(self, request, view):return request.method in SAFE_METHODSclass ExampleView(APIView):permission_classes = [IsAuthenticated|ReadOnly]def get(self, request, format=None):content = {'status': 'request was permitted'}return Response(content)
注意: 它支持&(和),|(或)和~(不是)。
如需自定义权限,需要继承 rest_framework.permissions.BasePermission 父类,并实现以下任何一种方法,或者全部
.has_permission(self, request, view): 是否可以访问视图,view 表示当前视图对象.has_object_permission(self, request, view, obj): 是否可以访问数据对象,view 表示当前视图,ojb 为数据对象如果应向请求授予访问权限,则应返回 True ,否则应返回 False.
如果测试失败,自定义权限将引发异常。若要更改与异常关联的错误消息,请直接在自定义权限上实现属性。
from rest_framework import permissionsclass CustomerAccessPermission(permissions.BasePermission):message = 'Adding customers not allowed.'def has_permission(self, request, view):...
下面是一个权限类示例,该权限类根据阻止列表检查传入请求的 IP 地址,并在 IP 被阻止时拒绝请求。
from rest_framework import permissionsclass BlocklistPermission(permissions.BasePermission):"""Global permission check for blocked IPs."""def has_permission(self, request, view):ip_addr = request.META['REMOTE_ADDR']blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()return not blocked
除了针对所有传入请求运行的全局权限外,您还可以创建对象级权限,这些权限仅针对影响特定对象实例的操作运行。例如:
class IsOwnerOrReadOnly(permissions.BasePermission):"""Object-level permission to only allow owners of an object to edit it.Assumes the model instance has an `owner` attribute."""def has_object_permission(self, request, view, obj):# Read permissions are allowed to any request,# so we'll always allow GET, HEAD or OPTIONS requests.if request.method in permissions.SAFE_METHODS:return True# Instance must have an attribute named `owner`.return obj.owner == request.user
限流 可以对接口的访问频次进行限制,以减轻服务器压力。
可以在配置文件中,使用 DEFAULT_THROTTLE_RATES 中进行全局配置。
REST_FRAMEWORK = {'DEFAULT_THROTTLE_CLASSES': [# 适用于任何用户对接口访问的限制'rest_framework.throttling.AnonRateThrottle',# 登录用户对接口访问的限制'rest_framework.throttling.UserRateThrottle'],'DEFAULT_THROTTLE_RATES': {'anon': '100/day','user': '1000/day'}
}
AnonRateThrottle: 限制所有匿名未认证的用户,使用 IP 区分用户。 UserRateThrottle:限制认证用户,使用 user_id 来区分ScopedRateThrottle: 限制用户对于每个视图访问频次,使用 IP 或者 user_id DEFAULT_THROTTLE_RATES 可以使用 second , minute,hour, 或者 day 来指定周期。
同样还可以基于每个视图或者每个视图集设置限流策略,使用基于类视图。
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIViewclass ExampleView(APIView):throttle_classes = [UserRateThrottle]def get(self, request, format=None):content = {'status': 'request was permitted'}return Response(content)
如果将装饰器 @api_view 与基于函数的视图一起使用,则可以使用以下装饰器。
@api_view(['GET'])
@throttle_classes([UserRateThrottle])
def example_view(request, format=None):content = {'status': 'request was permitted'}return Response(content)
还可以为使用 @action 装饰器创建的路由设置限制类。 以这种方式设置的限制类将覆盖任何视图集级别类设置。
@action(detail=True, methods=["post"], throttle_classes=[UserRateThrottle])
def example_adhoc_method(request, pk=None):content = {'status': 'request was permitted'}return Response(content)
REST_FRAMEWORK = {'DEFAULT_THROTTLE_CLASSES': ['rest_framework.throttling.ScopedRateThrottle'],'DEFAULT_THROTTLE_RATES': {'uploads': '100/day','contacts': '1000/day'}
}class ExampleView(APIView):throttle_scope = "contacts"
Filtering 可以针对列表数据根据字段进行过滤
您可能希望筛选查询集,以确保仅返回与发出请求的当前经过身份验证的用户相关的结果。我们可以 使用 request.user 来获取当前用户。
from myapp.models import Purchase
from myapp.serializers import PurchaseSerializer
from rest_framework import genericsclass PurchaseList(generics.ListAPIView):serializer_class = PurchaseSerializerdef get_queryset(self):"""This view should return a list of all the purchasesfor the currently authenticated user."""user = self.request.userreturn Purchase.objects.filter(purchaser=user)
另一种筛选方式可能涉及根据 URL 的某些部分限制查询集。例如
re_path('^purchases/(?P.+)/$', PurchaseList.as_view()),
然后,可以编写一个视图,该视图返回按 URL 的用户名部分筛选的查询集:
class PurchaseList(generics.ListAPIView):serializer_class = PurchaseSerializerdef get_queryset(self):"""This view should return a list of all the purchases forthe user as determined by the username portion of the URL."""username = self.kwargs['username']return Purchase.objects.filter(purchaser__username=username)
筛选初始查询集的最后一个示例是根据 url 中的查询参数确定初始查询集。
我们可以覆盖以处理诸如 ,并且仅当参数包含在 URL 中时才过滤查询集:.get_queryset()
http://example.com/api/purchases?username=denvercoder9username
class PurchaseList(generics.ListAPIView):serializer_class = PurchaseSerializerdef get_queryset(self):"""Optionally restricts the returned purchases to a given user,by filtering against a `username` query parameter in the URL."""queryset = Purchase.objects.all()username = self.request.query_params.get('username')if username is not None:queryset = queryset.filter(purchaser__username=username)return queryset
可以使用 DEFAULT_FILTER_BACKENDS 设置默认过滤器
REST_FRAMEWORK = {'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}
还可以按视图或视图集设置筛选器后端, 使用基于 GenericAPIView 类的视图。
import django_filters.rest_framework
from django.contrib.auth.models import User
from myapp.serializers import UserSerializer
from rest_framework import genericsclass UserListView(generics.ListAPIView):queryset = User.objects.all()serializer_class = UserSerializerfilter_backends = [django_filters.rest_framework.DjangoFilterBackend]
django-filter 库包含一个类 支持 REST 框架的高度可自定义 DjangoFilterBackend 字段筛选。
要使用 DjangoFilterBackend ,请先安装 django-filter
pip install django-filter
然后添加到 Django 的 INSTALLED_APPS :
INSTALLED_APPS = [...'django_filters',...
]
将筛选器后端添加到设置中:
REST_FRAMEWORK = {'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}
或者将过滤器后端添加到单个视图或视图集
from django_filters.rest_framework import DjangoFilterBackendclass UserListView(generics.ListAPIView):...filter_backends = [DjangoFilterBackend]
如果您只需要简单的基于相等的过滤,则可以在视图或视图集上设置 filterset_fields 属性,列出要过滤的字段集。
class ProductList(generics.ListAPIView):queryset = Product.objects.all()serializer_class = ProductSerializerfilter_backends = [DjangoFilterBackend]filterset_fields = ['category', 'in_stock']
设置了 filterset_fields ,则可以通过如下方式发送请求
http://example.com/api/products?category=clothing&in_stock=True
SearchFilter 类支持简单的基于单个查询参数的搜索,并且基于 Django 管理员的搜索功能。
from rest_framework import filtersclass UserListView(generics.ListAPIView):queryset = User.objects.all()serializer_class = UserSerializerfilter_backends = [filters.SearchFilter]search_fields = ['username', 'email']
客户端通过进行查询来筛选列表中的项目,例如:
默认搜索参数名为 search
http://example.com/api/users?search=russell
还可以使用查找 API 双下划线表示法对外键或 ManyToManyField 执行相关查找:
search_fields = ['username', 'email', 'profile__profession']
对于 JSONField 和 HStoreField 字段,您可以使用相同的双下划线表示法根据数据结构中的嵌套值进行筛选:
search_fields = ['data__breed', 'data__owner__other_pets__0__name']
默认情况下,搜索将使用不区分大小写的部分匹配。搜索参数可以包含多个搜索词,这些搜索词应以空格和/或逗号分隔。如果使用多个搜索词,则仅当提供的所有词都匹配时,才会在列表中返回对象。
可以通过在 search_fields 前面加上各种字符来限制搜索行为。
search_fields = ['=username', '=email']
OrderingFilter 类支持简单的查询参数控制的结果排序。默认情况下,查询参数名为 ordering
例如,要按用户名对用户进行排序:
http://example.com/api/users?ordering=username
客户端还可以通过在字段名称前面加上“-”来指定反向排序,如下所示:
http://example.com/api/users?ordering=-username
还可以指定多个排序:
http://example.com/api/users?ordering=account,username
建议显式指定 API 应在排序筛选器中允许哪些字段。您可以通过在视图上设置属性来执行此操作,如下所示:
class UserListView(generics.ListAPIView):queryset = User.objects.all()serializer_class = UserSerializerfilter_backends = [filters.OrderingFilter]ordering_fields = ['username', 'email']
这有助于防止意外的数据泄露,例如允许用户根据密码哈希字段或其他敏感数据进行排序。
如果未在视图上指定 ordering_fields 属性,则筛选器类将默认允许用户筛选属性指定的serializer_class 序列化程序上的任何可读字段。
如果确信视图使用的查询集不包含任何敏感数据,则还可以通过使用特殊值 __all__ 显式指定视图应允许对任何模型字段或查询集聚合进行排序。
class BookingsListView(generics.ListAPIView):queryset = Booking.objects.all()serializer_class = BookingSerializerfilter_backends = [filters.OrderingFilter]ordering_fields = '__all__'
如果在视图上设置了 ordering 属性,则将将其用作默认排序。
class UserListView(generics.ListAPIView):queryset = User.objects.all()serializer_class = UserSerializerfilter_backends = [filters.OrderingFilter]ordering_fields = ['username', 'email']ordering = ['username']
DRF 中也给我们提供了分页支持。
分页仅仅使用通用视图或视图集时,才会自动执行分页。注意如果使用的是常规 APIView ,则需要自行调用分页 API,以确保返回分页响应。
有关示例,可以参考 mixins.ListModelMixin 和 generics.GenericAPIView 类的源代码。
可以通过将分页类设置为 None 来关闭分页。
可以使用 DEFAULT_PAGINATION_CLASS 和 PAGE_SIZE 设置键全局设置分页样式。例如,要使用内置的限制/偏移分页,您可以执行以下操作:
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination','PAGE_SIZE': 100
}
如果要修改分页样式的特定方面,则需要覆盖其中一个分页类,并设置要更改的属性。
class LargeResultsSetPagination(PageNumberPagination):page_size = 1000page_size_query_param = 'page_size'max_page_size = 10000class StandardResultsSetPagination(PageNumberPagination):page_size = 100page_size_query_param = 'page_size'max_page_size = 1000
可以使用pagination_class 属性将新样式应用于视图:
class BillingRecordsView(generics.ListAPIView):queryset = Billing.objects.all()serializer_class = BillingRecordsSerializerpagination_class = LargeResultsSetPagination
或者使用 DEFAULT_PAGINATION_CLASS 设置键全局应用样式。例如:
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}
首先需要在 DEFAULT_PAGINATION_CLASS 和 PAGE_SIZE 设置键全局设置分页样式。
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination','PAGE_SIZE': 100
}
请求:
https://api.example.org/accounts/?page=4
响应:
HTTP 200 OK
{"count": 1023,"next": "https://api.example.org/accounts/?page=5","previous": "https://api.example.org/accounts/?page=3","results": […]
}
**注意 :如果我们在视图中需要关闭分页功能,可我们只需要在视图中 设置pagination_class 为 None **
pagination_class = None
PageNumberPagination 类包含许多属性,可以重写这些属性以修改 PageNumberPagination 分页样式。
若要设置这些属性,应重写 PageNumberPagination 类,然后启用自定义分页类,如上所示
Django Paginator类。默认值为 django.core.paginator.Paginator ,这对于大多数用例来说应该没问题。 PAGE_SIZE,这将覆盖该设置。默认为 PAGE_SIZE 与设置键相同的值。page_size_query_param此属性时,此属性才有效。 page_query_param要全局启用 LimitOffsetPagination 样式,请使用以下配置:
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination'
}
请求:
GET https://api.example.org/accounts/?limit=100&offset=400
响应:
HTTP 200 OK
{"count": 1023,"next": "https://api.example.org/accounts/?limit=100&offset=500","previous": "https://api.example.org/accounts/?limit=100&offset=300","results": […]
}
若要创建自定义分页序列化程序类,应继承 pagination.BasePagination 子类 ,重写 paginate_queryset(self, queryset, request, view=None) 和 get_paginated_response(self, data)方法:
class CustomPagination(pagination.PageNumberPagination):def get_paginated_response(self, data):return Response({'links': {'next': self.get_next_link(),'previous': self.get_previous_link()},'count': self.page.paginator.count,'results': data})
然后,我们需要在配置中设置自定义类:
REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'my_project.apps.core.pagination.CustomPagination','PAGE_SIZE': 100
}
REST 框架的视图处理各种异常,并处理返回适当的错误响应。
处理的异常包括:
APIException 异常Http404异常PermissionDenied 异常在每种情况下,REST 框架都将返回具有相应状态代码和内容类型的响应。响应正文将包含有关错误性质的任何其他详细信息。
DELETE http://api.example.com/foo/bar HTTP/1.1
Accept: application/json
可能会收到错误响应,指示 DELETE 方法不允许用于该资源:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 42{"detail": "Method 'DELETE' not allowed."}
验证错误的处理方式略有不同,并将 NON_FIELD_ERRORS_KEY 字段名称作为响应中的键包含在内。如果验证错误不是特定于特定字段的,则它将使用“non_field_errors”键或为设置设置的任何字符串值。
示例验证错误可能如下所示:
HTTP/1.1 400 Bad Request
Content-Type: application/json
Content-Length: 94{"amount": ["A valid integer is required."], "description": ["This field may not be blank."]}
例如,您可能希望确保所有错误响应在响应正文中包含 HTTP 状态代码,如下所示:
HTTP/1.1 405 Method Not Allowed
Content-Type: application/json
Content-Length: 62{"status_code": 405, "detail": "Method 'DELETE' not allowed."}
为了更改响应的样式,您可以编写以下自定义异常处理程序:
from rest_framework.views import exception_handlerdef custom_exception_handler(exc, context):# Call REST framework's default exception handler first,# to get the standard error response.response = exception_handler(exc, context)# Now add the HTTP status code to the response.if response is not None:response.data['status_code'] = response.status_codereturn response
还必须使用设置键在设置中 EXCEPTION_HANDLER 配置异常处理程序。例如:
REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler'
}
如果未指定 'EXCEPTION_HANDLER',则设置默认为 REST 框架提供的标准异常处理程序:
REST_FRAMEWORK = {'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
}
APIView 类或 @api_view 装饰器内引发的所有异常的基类。
如果要自定义 APIException 异常,需要在 APIException 类中设置 .status_code、 .default_detail 、default_code 属性。
from rest_framework.exceptions import APIExceptionclass ServiceUnavailable(APIException):status_code = 503default_detail = 'Service temporarily unavailable, try again later.'default_code = 'service_unavailable'
重写异常类之后,如果需要验证自定义的异常是否生效,可以使用如下方法
.detail - 返回错误的文本说明。.get_codes() - 返回错误的代码标识符。.get_full_details() - 返回文本描述和代码标识符。>>> print(exc.detail)
You do not have permission to perform this action.
>>> print(exc.get_codes())
permission_denied
>>> print(exc.get_full_details())
{'message':'You do not have permission to perform this action.','code':'permission_denied'}
在验证错误的情况下,错误详细信息将是一个列表或 词典:
>>> print(exc.detail)
{"name":"This field is required.","age":"A valid integer is required."}
>>> print(exc.get_codes())
{"name":"required","age":"invalid"}
>>> print(exc.get_full_details())
{"name":{"message":"This field is required.","code":"required"},"age":{"message":"A valid integer is required.","code":"invalid"}}
如果访问 request.data 时请求包含格式不正确的数据,则引发该异常。默认情况下,该异常会导致响应 HTTP 状态码 为 400
底层源码:
class ParseError(APIException):status_code = status.HTTP_400_BAD_REQUESTdefault_detail = _('Malformed request.')default_code = 'parse_error'
当传入请求包含不正确的身份验证时,如token鉴权失败,则引发的异常。默认情况下,认证失败响应状态码会返回 401,也有可能导致 403 禁止访问
class AuthenticationFailed(APIException):status_code = status.HTTP_401_UNAUTHORIZEDdefault_detail = _('Incorrect authentication credentials.')default_code = 'authentication_failed'
当未经身份验证的请求未通过权限检查时引发。默认情况下,认证失败响应状态码会返回 401,也有可能导致 403 禁止访问
class NotAuthenticated(APIException):status_code = status.HTTP_401_UNAUTHORIZEDdefault_detail = _('Authentication credentials were not provided.')default_code = 'not_authenticated'
当经过身份验证的请求未通过权限检查时引发。默认情况下,此异常会导致 HTTP 状态代码为“403 禁止访问”的响应。
class PermissionDenied(APIException):status_code = status.HTTP_403_FORBIDDENdefault_detail = _('You do not have permission to perform this action.')default_code = 'permission_denied'
当给定 URL 中不存在资源时引发。此异常等效于标准的 Django Http404 异常。
class MethodNotAllowed(APIException):status_code = status.HTTP_405_METHOD_NOT_ALLOWEDdefault_detail = _('Method "{method}" not allowed.')default_code = 'method_not_allowed'def __init__(self, method, detail=None, code=None):if detail is None:detail = force_str(self.default_detail).format(method=method)super().__init__(detail, code)
当发生未映射到视图上的处理程序方法的传入请求时引发。此异常会导致 HTTP 状态代码为“405 方法不允许”的响应。
class MethodNotAllowed(APIException):status_code = status.HTTP_405_METHOD_NOT_ALLOWEDdefault_detail = _('Method "{method}" not allowed.')default_code = 'method_not_allowed'def __init__(self, method, detail=None, code=None):if detail is None:detail = force_str(self.default_detail).format(method=method)super().__init__(detail, code)
当传入请求发生且标头 Accept 无法由任何可用呈现器满足时引发。
默认情况下,此异常会导致 HTTP 状态代码为“406 不可接受”的响应。
class NotAcceptable(APIException):status_code = status.HTTP_406_NOT_ACCEPTABLEdefault_detail = _('Could not satisfy the request Accept header.')default_code = 'not_acceptable'def __init__(self, detail=None, code=None, available_renderers=None):self.available_renderers = available_rendererssuper().__init__(detail, code)
如果没有解析器可以在访问 request.data 时处理请求数据的内容类型,则引发该异常。
默认情况下,此异常会导致响应 HTTP 状态代码“415 不支持的媒体类型”。
class UnsupportedMediaType(APIException):status_code = status.HTTP_415_UNSUPPORTED_MEDIA_TYPEdefault_detail = _('Unsupported media type "{media_type}" in request.')default_code = 'unsupported_media_type'def __init__(self, media_type, detail=None, code=None):if detail is None:detail = force_str(self.default_detail).format(media_type=media_type)super().__init__(detail, code)
当传入请求未通过限制检查时引发,默认情况下,此异常会导致响应 HTTP 状态代码为“429 请求过多”。
class Throttled(APIException):status_code = status.HTTP_429_TOO_MANY_REQUESTSdefault_detail = _('Request was throttled.')extra_detail_singular = _('Expected available in {wait} second.')extra_detail_plural = _('Expected available in {wait} seconds.')default_code = 'throttled'def __init__(self, wait=None, detail=None, code=None):if detail is None:detail = force_str(self.default_detail)if wait is not None:wait = math.ceil(wait)detail = ' '.join((detail,force_str(ngettext(self.extra_detail_singular.format(wait=wait),self.extra_detail_plural.format(wait=wait),wait))))self.wait = waitsuper().__init__(detail, code)
ValidationError 异常与 APIException 其他类略有不同。
detail 参数是必传的,并非选填detail 参数可以是错误详细信息的列表或字典,也可以是嵌套的数据结构。通过使用字典,可以在序列化程序的方法中执行对象级 validate() 验证时指定字段级错误。如 raise serializers.ValidationError({'name': 'Please enter a valid name.'})ValidationError 应用于序列化程序和字段验证,以及 serializer.is_valid 验证程序类。使用关键字 raise_exception` 参数调用时也会引发它:
serializer.is_valid(raise_exception=True)
通用视图使用 raise_exception=True 标志,这意味着您可以在 API 中全局覆盖验证错误响应的样式。为此,请使用自定义异常处理程序,如上所述。
默认情况下,此异常会导致响应 HTTP 状态代码为“400 错误请求”。
class ValidationError(APIException):status_code = status.HTTP_400_BAD_REQUESTdefault_detail = _('Invalid input.')default_code = 'invalid'def __init__(self, detail=None, code=None):if detail is None:detail = self.default_detailif code is None:code = self.default_code# For validation failures, we may collect many errors together,# so the details should always be coerced to a list if not already.if isinstance(detail, tuple):detail = list(detail)elif not isinstance(detail, dict) and not isinstance(detail, list):detail = [detail]self.detail = _get_error_details(detail, code)
Django REST 框架提供了两个错误视图,适用于提供通用的 JSON 服务器错误和错误请求响应。(Django 的默认错误视图提供了 HTML 响应,这可能不适合 仅限 API 的应用程序。)
Django 默认视图文档: Django 的自定义错误视图文档
返回具有状态代码 500 和application/json 为 application/json响应。
def server_error(request, *args, **kwargs):"""Generic 500 error handler."""data = {'error': 'Server Error (500)'}return JsonResponse(data, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
返回具有状态代码 400 和application/json 为 application/json响应。
def bad_request(request, exception, *args, **kwargs):"""Generic 400 error handler."""data = {'error': 'Bad Request (400)'}return JsonResponse(data, status=status.HTTP_400_BAD_REQUEST)
上一篇:C++基础——C++ 运算符
下一篇:怎样为SONiC社区做贡献