赞
踩
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 APIView
class 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 APIView
class 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 APIView class ReadOnly(BasePermission): def has_permission(self, request, view): return request.method in SAFE_METHODS class 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 permissions
class CustomerAccessPermission(permissions.BasePermission):
message = 'Adding customers not allowed.'
def has_permission(self, request, view):
...
下面是一个权限类示例,该权限类根据阻止列表检查传入请求的 IP 地址,并在 IP 被阻止时拒绝请求。
from rest_framework import permissions
class 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 APIView
class 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 generics
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
def get_queryset(self):
"""
This view should return a list of all the purchases
for the currently authenticated user.
"""
user = self.request.user
return Purchase.objects.filter(purchaser=user)
另一种筛选方式可能涉及根据 URL 的某些部分限制查询集。例如
re_path('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
然后,可以编写一个视图,该视图返回按 URL 的用户名部分筛选的查询集:
class PurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
def get_queryset(self):
"""
This view should return a list of all the purchases for
the 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 = PurchaseSerializer
def 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 generics
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_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 DjangoFilterBackend
class UserListView(generics.ListAPIView):
...
filter_backends = [DjangoFilterBackend]
如果您只需要简单的基于相等的过滤,则可以在视图或视图集上设置 filterset_fields
属性,列出要过滤的字段集。
class ProductList(generics.ListAPIView):
queryset = Product.objects.all()
serializer_class = ProductSerializer
filter_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 filters
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_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 = UserSerializer
filter_backends = [filters.OrderingFilter]
ordering_fields = ['username', 'email']
这有助于防止意外的数据泄露,例如允许用户根据密码哈希字段或其他敏感数据进行排序。
如果未在视图上指定 ordering_fields
属性,则筛选器类将默认允许用户筛选属性指定的serializer_class
序列化程序上的任何可读字段。
如果确信视图使用的查询集不包含任何敏感数据,则还可以通过使用特殊值 __all__
显式指定视图应允许对任何模型字段或查询集聚合进行排序。
class BookingsListView(generics.ListAPIView):
queryset = Booking.objects.all()
serializer_class = BookingSerializer
filter_backends = [filters.OrderingFilter]
ordering_fields = '__all__'
如果在视图上设置了 ordering
属性,则将将其用作默认排序。
class UserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_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 = 1000
page_size_query_param = 'page_size'
max_page_size = 10000
class StandardResultsSetPagination(PageNumberPagination):
page_size = 100
page_size_query_param = 'page_size'
max_page_size = 1000
可以使用pagination_class
属性将新样式应用于视图:
class BillingRecordsView(generics.ListAPIView):
queryset = Billing.objects.all()
serializer_class = BillingRecordsSerializer
pagination_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_handler
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)
# Now add the HTTP status code to the response.
if response is not None:
response.data['status_code'] = response.status_code
return 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 APIException
class ServiceUnavailable(APIException):
status_code = 503
default_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_REQUEST
default_detail = _('Malformed request.')
default_code = 'parse_error'
当传入请求包含不正确的身份验证时,如token鉴权失败,则引发的异常。默认情况下,认证失败响应状态码会返回 401,也有可能导致 403 禁止访问
class AuthenticationFailed(APIException):
status_code = status.HTTP_401_UNAUTHORIZED
default_detail = _('Incorrect authentication credentials.')
default_code = 'authentication_failed'
当未经身份验证的请求未通过权限检查时引发。默认情况下,认证失败响应状态码会返回 401,也有可能导致 403 禁止访问
class NotAuthenticated(APIException):
status_code = status.HTTP_401_UNAUTHORIZED
default_detail = _('Authentication credentials were not provided.')
default_code = 'not_authenticated'
当经过身份验证的请求未通过权限检查时引发。默认情况下,此异常会导致 HTTP 状态代码为“403 禁止访问”的响应。
class PermissionDenied(APIException):
status_code = status.HTTP_403_FORBIDDEN
default_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_ALLOWED
default_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_ALLOWED
default_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_ACCEPTABLE
default_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_renderers
super().__init__(detail, code)
如果没有解析器可以在访问 request.data
时处理请求数据的内容类型,则引发该异常。
默认情况下,此异常会导致响应 HTTP 状态代码“415 不支持的媒体类型”。
class UnsupportedMediaType(APIException):
status_code = status.HTTP_415_UNSUPPORTED_MEDIA_TYPE
default_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_REQUESTS default_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 = wait super().__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_REQUEST default_detail = _('Invalid input.') default_code = 'invalid' def __init__(self, detail=None, code=None): if detail is None: detail = self.default_detail if 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)
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。