认证 Authentication
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
classExampleView(APIView):
authentication_classes =[SessionAuthentication, BasicAuthentication]
permission_classes =[IsAuthenticated]defget(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])defexample_view(request,format=None):
content ={'user':str(request.user),# `django.contrib.auth.User` instance.'auth':str(request.auth),# None}return Response(content)
认证失败通常会有两种响应:
- HTTP 401 Unauthorized 未认证
- HTTP 403 Permission Denied 权限被禁止
权限 Permissions
权限控制可以限制用于对于视图的访问和对于具体数据对象的访问。
- 在 执行视图的 dispatch() 方法前,会先进行视图访问权限的判断。
- 在通过 get_object() 获取具体对象时,会进行对象访问权限的判断。
设置权限策略
可以使用该设置全局设置默认
DEFAULT_PERMISSION_CLASSES
权限策略。例如
REST_FRAMEWORK ={'DEFAULT_PERMISSION_CLASSES':['rest_framework.permissions.IsAuthenticated',]}
如果配置文件中未指明,则设置默认为允许无限制访问
'DEFAULT_PERMISSION_CLASSES':['rest_framework.permissions.AllowAny',]
DRF中提供的权限策略
AllowAny
允许所有用户IsAuthenticated
仅通过认证的用户IsAdminUser
仅管理员用户IsAuthenticatedOrReadOnly
认证的用户可以完全操作,否则只能 Get 读取
还可以基于每个视图或者每个视图集设置身份验证策略,使用基于
APIView
类的视图。
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
classExampleView(APIView):
permission_classes =[IsAuthenticated]defget(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])defexample_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
classReadOnly(BasePermission):defhas_permission(self, request, view):return request.method in SAFE_METHODS
classExampleView(APIView):
permission_classes =[IsAuthenticated|ReadOnly]defget(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
classCustomerAccessPermission(permissions.BasePermission):
message ='Adding customers not allowed.'defhas_permission(self, request, view):...
示例
下面是一个权限类示例,该权限类根据阻止列表检查传入请求的 IP 地址,并在 IP 被阻止时拒绝请求。
from rest_framework import permissions
classBlocklistPermission(permissions.BasePermission):"""
Global permission check for blocked IPs.
"""defhas_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()returnnot blocked
除了针对所有传入请求运行的全局权限外,您还可以创建对象级权限,这些权限仅针对影响特定对象实例的操作运行。例如:
classIsOwnerOrReadOnly(permissions.BasePermission):"""
Object-level permission to only allow owners of an object to edit it.
Assumes the model instance has an `owner` attribute.
"""defhas_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:returnTrue# Instance must have an attribute named `owner`.return obj.owner == request.user
限流 Throttling
限流 可以对接口的访问频次进行限制,以减轻服务器压力。
设置限流策略
可以在配置文件中,使用
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
classExampleView(APIView):
throttle_classes =[UserRateThrottle]defget(self, request,format=None):
content ={'status':'request was permitted'}return Response(content)
如果将装饰器
@api_view
与基于函数的视图一起使用,则可以使用以下装饰器。
@api_view(['GET'])@throttle_classes([UserRateThrottle])defexample_view(request, format=None):
content ={'status':'request was permitted'}return Response(content)
还可以为使用
@action
装饰器创建的路由设置限制类。 以这种方式设置的限制类将覆盖任何视图集级别类设置。
@action(detail=True, methods=["post"], throttle_classes=[UserRateThrottle])defexample_adhoc_method(request, pk=None):
content ={'status':'request was permitted'}return Response(content)
ScopedRateThrottle 自定义限流
REST_FRAMEWORK ={'DEFAULT_THROTTLE_CLASSES':['rest_framework.throttling.ScopedRateThrottle'],'DEFAULT_THROTTLE_RATES':{'uploads':'100/day','contacts':'1000/day'}}classExampleView(APIView):
throttle_scope ="contacts"
过滤 Filtering
Filtering 可以针对列表数据根据字段进行过滤
针对当前用户进行筛选
您可能希望筛选查询集,以确保仅返回与发出请求的当前经过身份验证的用户相关的结果。我们可以 使用
request.user
来获取当前用户。
from myapp.models import Purchase
from myapp.serializers import PurchaseSerializer
from rest_framework import generics
classPurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
defget_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 的用户名部分筛选的查询集:
classPurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
defget_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
classPurchaseList(generics.ListAPIView):
serializer_class = PurchaseSerializer
defget_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 isnotNone:
queryset = queryset.filter(purchaser__username=username)return queryset
Generic Filtering 通用筛选
可以使用
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
classUserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends =[django_filters.rest_framework.DjangoFilterBackend]
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
classUserListView(generics.ListAPIView):...
filter_backends =[DjangoFilterBackend]
如果您只需要简单的基于相等的过滤,则可以在视图或视图集上设置
filterset_fields
属性,列出要过滤的字段集。
classProductList(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 搜索过滤器
SearchFilter
类支持简单的基于单个查询参数的搜索,并且基于 Django 管理员的搜索功能。
from rest_framework import filters
classUserListView(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
前面加上各种字符来限制搜索行为。
- “^” 从搜索开始。
- “=”完全匹配。
- “@”全文搜索。(目前仅支持 Django 的 PostgreSQL 后端。)
- ‘$’ 正则表达式搜索。
search_fields =['=username','=email']
OrderingFilter 排序过滤器
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 应在排序筛选器中允许哪些字段。您可以通过在视图上设置属性来执行此操作,如下所示:
classUserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends =[filters.OrderingFilter]
ordering_fields =['username','email']
这有助于防止意外的数据泄露,例如允许用户根据密码哈希字段或其他敏感数据进行排序。
如果未在视图上指定
ordering_fields
属性,则筛选器类将默认允许用户筛选属性指定的
serializer_class
序列化程序上的任何可读字段。
如果确信视图使用的查询集不包含任何敏感数据,则还可以通过使用特殊值
__all__
显式指定视图应允许对任何模型字段或查询集聚合进行排序。
classBookingsListView(generics.ListAPIView):
queryset = Booking.objects.all()
serializer_class = BookingSerializer
filter_backends =[filters.OrderingFilter]
ordering_fields ='__all__'
指定默认排序
如果在视图上设置了
ordering
属性,则将将其用作默认排序。
classUserListView(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
filter_backends =[filters.OrderingFilter]
ordering_fields =['username','email']
ordering =['username']
分页 Pagination
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}
如果要修改分页样式的特定方面,则需要覆盖其中一个分页类,并设置要更改的属性。
classLargeResultsSetPagination(PageNumberPagination):
page_size =1000
page_size_query_param ='page_size'
max_page_size =10000classStandardResultsSetPagination(PageNumberPagination):
page_size =100
page_size_query_param ='page_size'
max_page_size =1000
可以使用
pagination_class
属性将新样式应用于视图:
classBillingRecordsView(generics.ListAPIView):
queryset = Billing.objects.all()
serializer_class = BillingRecordsSerializer
pagination_class = LargeResultsSetPagination
或者使用
DEFAULT_PAGINATION_CLASS
设置键全局应用样式。例如:
REST_FRAMEWORK ={'DEFAULT_PAGINATION_CLASS':'apps.core.pagination.StandardResultsSetPagination'}
PageNumberPagination 页码分页
首先需要在
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_class: 要使用的
Django Paginator
类。默认值为django.core.paginator.Paginator
,这对于大多数用例来说应该没问题。 - page_size:指示页面大小的数值。如果设置
PAGE_SIZE
,这将覆盖该设置。默认为PAGE_SIZE
与设置键相同的值。 - page_query_param: 一个字符串值,指示要用于分页控件的查询参数的名称。
- page_size_query_param: 如果设置,则这是一个字符串值,指示允许客户端基于每个请求设置页面大小的查询参数的名称。默认值为 None ,表示客户端可能无法控制请求的页面大小。
- max_page_size: 如果设置,则这是一个数值,指示允许的最大请求页面大小。仅当还设置了
page_size_query_param
此属性时,此属性才有效。 - last_page_strings:字符串值的列表或元组,指示可与 一起使用以请求集合中的最后一页的值。默认值
page_query_param
LimitOffsetPagination 偏移分页
要全局启用
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)
方法:
classCustomPagination(pagination.PageNumberPagination):defget_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}
异常处理 Exception
REST 框架的视图处理各种异常,并处理返回适当的错误响应。
处理的异常包括:
- 在 REST 框架中引发的
APIException
异常 - Django的
Http404
异常 - Django的
PermissionDenied
异常
在每种情况下,REST 框架都将返回具有相应状态代码和内容类型的响应。响应正文将包含有关错误性质的任何其他详细信息。
DELETE http://api.example.com/foo/bar HTTP/1.1
Accept: application/json
可能会收到错误响应,指示
DELETE
方法不允许用于该资源:
HTTP/1.1405 Method Not Allowed
Content-Type: application/json
Content-Length:42{"detail":"Method 'DELETE' not allowed."}
验证错误的处理方式略有不同,并将
NON_FIELD_ERRORS_KEY
字段名称作为响应中的键包含在内。如果验证错误不是特定于特定字段的,则它将使用
“non_field_errors”
键或为设置设置的任何字符串值。
示例验证错误可能如下所示:
HTTP/1.1400 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.1405 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
defcustom_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 isnotNone:
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'}
APIException
APIView
类或
@api_view
装饰器内引发的所有异常的基类。
如果要自定义
APIException
异常,需要在
APIException
类中设置
.status_code
、
.default_detail
、
default_code
属性。
from rest_framework.exceptions import APIException
classServiceUnavailable(APIException):
status_code =503
default_detail ='Service temporarily unavailable, try again later.'
default_code ='service_unavailable'
检查 API 异常
重写异常类之后,如果需要验证自定义的异常是否生效,可以使用如下方法
.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"}}
ParseError 解析异常
如果访问
request.data
时请求包含格式不正确的数据,则引发该异常。默认情况下,该异常会导致响应 HTTP 状态码 为 400
底层源码:
classParseError(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = _('Malformed request.')
default_code ='parse_error'
AuthenticationFailed 认证失败异常
当传入请求包含不正确的身份验证时,如token鉴权失败,则引发的异常。默认情况下,认证失败响应状态码会返回 401,也有可能导致
403 禁止访问
classAuthenticationFailed(APIException):
status_code = status.HTTP_401_UNAUTHORIZED
default_detail = _('Incorrect authentication credentials.')
default_code ='authentication_failed'
NotAuthenticated 未认证
当未经身份验证的请求未通过权限检查时引发。默认情况下,认证失败响应状态码会返回 401,也有可能导致
403 禁止访问
classNotAuthenticated(APIException):
status_code = status.HTTP_401_UNAUTHORIZED
default_detail = _('Authentication credentials were not provided.')
default_code ='not_authenticated'
PermissionDenied 权限拒绝
当经过身份验证的请求未通过权限检查时引发。默认情况下,此异常会导致 HTTP 状态代码为“403 禁止访问”的响应。
classPermissionDenied(APIException):
status_code = status.HTTP_403_FORBIDDEN
default_detail = _('You do not have permission to perform this action.')
default_code ='permission_denied'
NotFound
当给定 URL 中不存在资源时引发。此异常等效于标准的 Django
Http404
异常。
classMethodNotAllowed(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 isNone:
detail = force_str(self.default_detail).format(method=method)super().__init__(detail, code)
MethodNotAllowed
当发生未映射到视图上的处理程序方法的传入请求时引发。此异常会导致 HTTP 状态代码为“405 方法不允许”的响应。
classMethodNotAllowed(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 isNone:
detail = force_str(self.default_detail).format(method=method)super().__init__(detail, code)
NotAcceptable
当传入请求发生且标头
Accept
无法由任何可用呈现器满足时引发。
默认情况下,此异常会导致 HTTP 状态代码为“406 不可接受”的响应。
classNotAcceptable(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)
UnsupportedMediaType
如果没有解析器可以在访问
request.data
时处理请求数据的内容类型,则引发该异常。
默认情况下,此异常会导致响应 HTTP 状态代码“415 不支持的媒体类型”。
classUnsupportedMediaType(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 isNone:
detail = force_str(self.default_detail).format(media_type=media_type)super().__init__(detail, code)
Throttled
当传入请求未通过限制检查时引发,默认情况下,此异常会导致响应 HTTP 状态代码为“429 请求过多”。
classThrottled(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 isNone:
detail = force_str(self.default_detail)if wait isnotNone:
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
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 错误请求”。
classValidationError(APIException):
status_code = status.HTTP_400_BAD_REQUEST
default_detail = _('Invalid input.')
default_code ='invalid'def__init__(self, detail=None, code=None):if detail isNone:
detail = self.default_detail
if code isNone:
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.ifisinstance(detail,tuple):
detail =list(detail)elifnotisinstance(detail,dict)andnotisinstance(detail,list):
detail =[detail]
self.detail = _get_error_details(detail, code)
Generic Error Views
Django REST 框架提供了两个错误视图,适用于提供通用的 JSON 服务器错误和错误请求响应。(Django 的默认错误视图提供了 HTML 响应,这可能不适合 仅限 API 的应用程序。)
Django 默认视图文档: Django 的自定义错误视图文档
返回具有状态代码
500
和
application/json
为
application/json
响应。
defserver_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
响应。
defbad_request(request, exception,*args,**kwargs):"""
Generic 400 error handler.
"""
data ={'error':'Bad Request (400)'}return JsonResponse(data, status=status.HTTP_400_BAD_REQUEST)
版权归原作者 七月的小尾巴 所有, 如有侵权,请联系我们删除。