- Requests
- RestFramewok 的Request 扩展了Django 的HttpRequest ,其他Django 的属性也使用
- request.META
- request.session
- request.data 包括所有提交(post patch)的数据(request.POST request.FILES)
- request.query_params request.GET (django) .query_params 会获取所有的方法提交的参数,而不仅仅是 get
- request.parsers 将此属性自动设置为解析器实例的列表。通常不需要访问
- request.user 返回用户实例,登录用户为
django.contrib.auth.models.User,非登录用户为
django.contrib.auth.models.AnonymousUser
. - request.auth 返回 token 或者session ,未登录则返回None
- request.authenticators 将此属性自动设置为Authentication实例列表。通常不需要访问
- request.method 返回请求的方法
- request.content_type 返回请求正文的媒体类型字符串对象
- Response
- Response 是Django的SimpleTemplateResponse的子类、
Response(data, status=None, template_name=None, headers=None, content_type=None)
- Response.data 序列化对象
- Response.status_code 返回的状态码
- Response.content 响应的呈现内容。 必须先调用.render()方法,然后才能访问.content。
- Response.template_name 模板名
- Response.accepted_media_type 内容协商阶段选择的媒体类型,从视图返回响应前由APIView 自动设置
- Response.render_context 附加上下文信息的词典,该词典将传递给渲染器的.render()方法。从视图返回响应之前,由APIView或@api_view自动设置。
- 标准的HttpResponse 属性
-
response = Response()
response['Cache-Control'] = 'no-cache'
- Response.render() 通常不用自己调
-
- Class-based View
- 继承自Django 的 View
- Request 和Rsponse 实例,而不是Django 的
- 任何APIException 异常将会捕获并给予适当的响应
- 在将请求分派到处理程序方法前,对传入的请求进行身份验证和适当的权限检查
- 可在类上设置许多属性,以控制API 策略的各个方面
- 范例
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework import authentication, permissions from django.contrib.auth.models import User class ListUsers(APIView): """ View to list all users in the system. * Requires token authentication. * Only admin users are able to access this view. """ authentication_classes = [authentication.TokenAuthentication] permission_classes = [permissions.IsAdminUser] def get(self, request, format=None): """ Return a list of all users. """ usernames = [user.username for user in User.objects.all()] return Response(usernames)
- APIView 的相关属性,重写这些类,在视图中引用仅在视图中有效,在setting 中配置,全局有效
- .render_classes
- .paser_classes
- .authentication_calsses
- .throttle_classes
- .permission_classes
- .content_negotiation_class
- API 策略实例方法,一般不重写
- .get_renders(self)
- .get_parsers(self)
- .get_authenticators(self)
- .get_throttles(self)
- .getpermissions(self)
- .get_content_negotiator(self)
- .get_exception_handler(self)
- API 策略实施方法
- 以下方法在分发到处理程序前,将会被调用
- .check_permissions(self,request)
- check_throttles(self,request)
- .perform_content_negotiation(self,request,force=False)
- dispatch分发方法
- .inital(self,request,*args,**kwargs) 执行在调用处理程序方法之前需要执行的所有操作。 此方法用于强制执行权限和限制,并执行内容协商。一般不需要重写
- .handle_exception(self,exc) 如果您需要自定义错误响应,那么您的API返回的值应该子类化此方法。
- .initialize_request(self,request,*args,**kwargs) 不需要重写
- .finalize_response(self,request,response,*args,**kwargs) 不需要重写
- Based View 方法
- @api_view() 如果什么都没写,就仅允许get
-
@api_view(['GET', 'POST']) def hello_world(request): if request.method == 'POST': return Response({"message": "Got some data!", "data": request.data}) return Response({"message": "Hello, world!"})
- API 策略装饰器
- 访问次数
@throttle_classes
from rest_framework.decorators import api_view, throttle_classes from rest_framework.throttling import UserRateThrottle class OncePerDayUserThrottle(UserRateThrottle): rate = '1/day' @api_view(['GET']) @throttle_classes([OncePerDayUserThrottle]) def view(request): return Response({"message": "Hello for today! See you tomorrow!"})
@renderer_classes(...)
@parser_classes(...)
@authentication_classes(...)
@throttle_classes(...)
@permission_classes(...)
- 访问次数
- View schema decorator
- 使用@schema 装饰器 覆盖基于函数的类视图的默认架构,必须在@api_view 装饰器后进行
rom rest_framework.decorators import api_view, schema from rest_framework.schemas import AutoSchema class CustomAutoSchema(AutoSchema): def get_link(self, path, method, base_url): # override view introspection here... @api_view(['GET']) @schema(CustomAutoSchema()) def view(request): return Response({"message": "Hello for today! See you tomorrow!"})
- 使用@schema 装饰器 覆盖基于函数的类视图的默认架构,必须在@api_view 装饰器后进行
- Generic Views
- 继承Generics 相关类
- 重写 queryset
- 重写 serializer_class
- 重写permission_classes
-
from django.contrib.auth.models import User from myapp.serializers import UserSerializer from rest_framework import generics from rest_framework.permissions import IsAdminUser class UserList(generics.ListCreateAPIView): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [IsAdminUser]
- 重写list
class UserList(generics.ListCreateAPIView): queryset = User.objects.all() serializer_class = UserSerializer permission_classes = [IsAdminUser] def list(self, request): # Note the use of `get_queryset()` instead of `self.queryset` queryset = self.get_queryset() serializer = UserSerializer(queryset, many=True) return Response(serializer.data)
- 使用as_view() 传递类属性
url(r'^/users/', ListCreateAPIView.as_view(queryset=User.objects.all(), serializer_class=UserSerializer), name='user-list')
- 属性
- queryset 用于从视图返回对象的查询集,通常必须设置此属性或者重写 get_queryset() 方法如果要覆盖视图方法,则必须用get_queryset(),而不是直接访问此属性,因为 queryset 已经被计算一次了,缓存结果将被用于后续请求
- serializer_class ,通常必须写此属性,或者重写 get_serializer_class()方法
- lookup_field 默认为 pk , 对象查找时,改变原本的主键为需要查询的属性
- lookup_url_kwarg 用于对象查找的URL 关键字参数,URL conf应包含与此值相对应的关键字参数。 如果未设置,则默认使用与lookup_field相同的值。
- pagination_class :默认值与DEFALT_PAGINATION_CLASS 设置相同的值,即rest_framework.pagination.PageNumberPagination”,设置pagination_class = None将禁用此视图上的分页。
- filter_backends 过滤查询集 默认为 DEFAULT_FILTER_BACKENDS
- 方法
- get_queryset(self) 重写方法后 ,使用不要使用,self.queryset
- get_object(self) 返回应用于详情视图的对象实例,默认为使用lookup_filed 过滤后的查询集
- filter_queryset(self,queryset) 使用filter backens 过滤请求,
ef filter_queryset(self, queryset): filter_backends = [CategoryFilter] if 'geo_route' in self.request.query_params: filter_backends = [GeoRouteFilter, CategoryFilter] elif 'geo_point' in self.request.query_params: filter_backends = [GeoPointFilter, CategoryFilter] for backend in list(filter_backends): queryset = backend().filter_queryset(self.request, queryset, view=self) return queryset
- get_serializer_class(self) 返回将被使用的序列化函数,可对其重写,用作不同条件下返回不同的对象
-
def get_serializer_class(self): if self.request.user.is_staff: return FullAccountSerializer return BasicAccountSerializer
-
- 钩子函数创建,更新,删除前 DestroyModelMixin 会调用
- perform_create(self,serializer ) createModelMixin
- perform_update(self,serializer) UpdtateModelMixn
- perform_destroy(self,instance) destroyMdelMixin
- 基于用户请求或者关键字
def perform_create(self, serializer): serializer.save(user=self.request.user)
- 保存对象前后,增加属性
- 保存对象后发送邮件,或者更新记录
def perform_update(self, serializer): instance = serializer.save() send_email_confirmation(user=self.request.user, modified=instance)
- 保存对象后发送邮件,或者更新记录
- 用这些钩子函数做额外的验证,使用ValidtationError()
-
def perform_create(self, serializer): queryset = SignupRequest.objects.filter(user=self.request.user) if queryset.exists(): raise ValidationError('You have already signed up') serializer.save(user=self.request.user)
-
- 其他方法
get_serializer_context(self) 返回包含应提供给序列化程序的任何其他上下文的字典。 默认情况下包括“请求”,“视图”和“格式”键。
get_serializer(self, instance=None, data=None, many=False, partial=False) 返回一个序列化实例
get_paginated_response(self, data) 返回一个分页格式对象
paginate_queryset(self, queryset) 对queryset 分页
filter_queryset(self, queryset) 使用 filter backends 对queryset 过滤,返回一个新的queryset
- Mixins类提供用于提供基本视图行为的操作,如get post 等方法,不需要重新定义
- ListModelMixin 提供了 list(request,*args,**kwargs),成功则返回200,数据可被选择地分页
- CreateModelMixin 提供了
create(request, *args, **kwargs) 创建和保存新模型,成功返回201,不成功400 bad request
- RetrieveModelMixin 提供了
.retrieve(request, *args, **kwargs) 详情,成功200,否则404Not found
- UpdateModelMixin 提供了
update(request, *args, **kwargs)和
partial_update(request, *args, **kwargs)方法,更新与部分更新,成功200,否则400 Bad Request
- DestroyModelMixin
destroy(request, *args, **kwargs) 删除 ,204 No Content,404 Not Found
- Generics 通用视图
- CreateAPIView 继承GenericAPIView,CreateModelMixn 提供post
- ListAPIView 继承GenericAPIView, ListModelMixin 提供get
- RetriveAPIView 继承GenericAPIView, RetrieveModelMixin ,提供get
- DestroyAPIView 继承GenericAPIView, DestroyModelMixin ,提供 delete
- UpdateAPIView 继承GenericAPIView, UpdateModelMixin 提供put 和patch
- ListCreateAPIView 继承GenericAPIView, ListModelMixin, CreateModelMixin 提供get 和post
- RetrieveUpdateAPIView 继承GenericAPIView, RetrieveModelMixin, UpdateModelMixin ,提供get put patch
- RetrieveDestroyAPIvIEW 继承GenericAPIView, RetrieveModelMixin, DestroyModelMixin ,提供 get delete
- RetrieveUpdateDestryoyAPIView 继承GenericAPIView, RetrieveModelMixin, UpdateModelMixin, DestroyModelMixin,提供get put patch delete
- 自定义通用视图
- 将该行为重构为一个通用类,然后可以根据需要将其仅应用于任何视图或视图集。
- 例如,如果您需要基于URL conf中的多个字段查找对象,则可以创建如下的mixin类:
class MultipleFieldLookupMixin: """ Apply this mixin to any view or viewset to get multiple field filtering based on a `lookup_fields` attribute, instead of the default single field filtering. """ def get_object(self): queryset = self.get_queryset() # Get the base queryset queryset = self.filter_queryset(queryset) # Apply any filter backends filter = {} for field in self.lookup_fields: if self.kwargs[field]: # Ignore empty fields. filter[field] = self.kwargs[field] obj = get_object_or_404(queryset, **filter) # Lookup the object self.check_object_permissions(self.request, obj) return obj
- 使用该自定义视图
-
class RetrieveUserView(MultipleFieldLookupMixin, generics.RetrieveAPIView): queryset = User.objects.all() serializer_class = UserSerializer lookup_fields = ['account', 'username']
-
- 创建自己的通用视图
-
class BaseRetrieveView(MultipleFieldLookupMixin, generics.RetrieveAPIView): pass class BaseRetrieveUpdateDestroyView(MultipleFieldLookupMixin, generics.RetrieveUpdateDestroyAPIView): pass
-
- ViewSets
- Django REST框架允许您在一个称为ViewSet的类中将一组相关视图的逻辑组合在一起
- ViewSet类只是基于类的View的一种,它不提供任何方法处理程序,例如.get()或.post(),而是提供诸如.list()和.create()的操作。
- 使用.as_view()方法,仅在最终确定视图时将ViewSet的方法处理程序绑定到相应的操作。
- 通常,您将向路由器集注册视图集,而不是在urlconf中的视图集中显式注册视图,而是自动为您确定urlconf
- 路由 >> as_view() 将 get 和list 绑定,我们仅使用 router 注册路由即可实现绑定
-
from myapp.views import UserViewSet from rest_framework.routers import DefaultRouter router = DefaultRouter() router.register(r'users', UserViewSet, basename='user') urlpatterns = router.urls
-
- 我们不需要自己定义list 或 retrieve 方法
- 只需要继承viewset.ModelViewSet
-
class UserViewSet(viewsets.ModelViewSet): """ A viewset for viewing and editing user instances. """ serializer_class = UserSerializer queryset = User.objects.all()
- 使用 ViewSet 的优势
- 重复的逻辑可以合并为一个类。 在上面的示例中,我们只需要指定一次queryset,它将在多个视图中使用。
通过使用路由器,我们不再需要自己处理URL conf。
- 重复的逻辑可以合并为一个类。 在上面的示例中,我们只需要指定一次queryset,它将在多个视图中使用。
- REST框架随附的默认路由器将为一组标准的创建/检索/更新/销毁样式操作提供路由,
-
class UserViewSet(viewsets.ViewSet): """ Example empty viewset demonstrating the standard actions that will be handled by a router class. If you're using format suffixes, make sure to also include the `format=None` keyword argument for each action. """ def list(self, request): pass def create(self, request): pass def retrieve(self, request, pk=None): pass def update(self, request, pk=None): pass def partial_update(self, request, pk=None): pass def destroy(self, request, pk=None): pass
-
- Introspecting ViewSet actions
- basename Url 的名字
- action 当前动作(list create)
- detail 布尔值,list 为False ,detail 为true
- suffiix 视图集类型的后缀镜像属性
- name Viewset 展示的名字,此参数与后缀互斥
- description 视图集的单个视图的显示描述
- 举例,你可能仅在list 视图不需要admin 权限,其他视图都需要管理员权限
def get_permissions(self): """ Instantiates and returns the list of permissions that this view requires. """ if self.action == 'list': permission_classes = [IsAuthenticated] else: permission_classes = [IsAdmin] return [permission() for permission in permission_classes]
- 给路由创建额外的action
- 如果有可路由的临时方法,则可使用@action 装饰器将其标记为可路由
- 像常规操作一样,额外的操作可能用于单个对象或者整个集合
- 将detail 设置为True或者False,路由器将相应地配置其URL 模式
- 例如DefaultRouter将配置详细操作以在其网址格式中包含PK
- 示例
from django.contrib.auth.models import User from rest_framework import status, viewsets from rest_framework.decorators import action from rest_framework.response import Response from myapp.serializers import UserSerializer, PasswordSerializer class UserViewSet(viewsets.ModelViewSet): """ A viewset that provides the standard actions """ queryset = User.objects.all() serializer_class = UserSerializer @action(detail=True, methods=['post']) def set_password(self, request, pk=None): user = self.get_object() serializer = PasswordSerializer(data=request.data) if serializer.is_valid(): user.set_password(serializer.data['password']) user.save() return Response({'status': 'password set'}) else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) @action(detail=False) def recent_users(self, request): recent_users = User.objects.all().order_by('-last_login') page = self.paginate_queryset(recent_users) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(recent_users, many=True) return Response(serializer.data)
- 还可以带个参数
-
@action(detail=True, methods=['post'], permission_classes=[IsAdminOrIsSelf]) def set_password(self, request, pk=None):
-
methods 默认为get ,要添加其他的方法可增加 methods 参数
-
^users/{pk}/set_password/$
^users/{pk}/unset_password/$ 路由满足此规律时,将调用
get_extra_actions()
- 额外的操作可以将其他的Http 方法映射到单独的ViewSet方法
- 例如可以将上述密码 设置/取消合并为一条路由,其他映射不接受任何参数
@action(detail=True, methods=['put'], name='Change Password') def password(self, request, pk=None): """Update the user's password.""" ... @password.mapping.delete def delete_password(self, request, pk=None): """Delete the user's password."""
- Reversing action URLs
- reverse_action() 获取action 的路由 ,使用basename
>>> view.reverse_action('set-password', args=['1']) 'http://localhost:8000/api/users/1/set_password'
- 使用@action 中的url_name
>>> view.reverse_action(view.set_password.url_name, args=['1']) 'http://localhost:8000/api/users/1/set_password'
- reverse_action() 获取action 的路由 ,使用basename
- API Refernce
- ViewSet
- Viewset 的class 继承自APIView 可以用permission_classes authentication_classes 控制,没有创建其他的新class
- GenericViewSet
- GenericViewSet的 class 继承自GenericAPIView ,提供了 get_object,get_queryset 方法和其他方法,但没有自己创建新的方法
- ModelViewSet
- ModelViewSet继承GenericAPIView ,并通过混合各种 Mixins 类的行为来包括所有动作的实现
ModelViewSet提供的动作有 list(),retrieve create update(),partial_update destroy()
-
class AccountViewSet(viewsets.ModelViewSet): """ A simple ViewSet for viewing and editing accounts. """ queryset = Account.objects.all() serializer_class = AccountSerializer permission_classes = [IsAccountAdminOrReadOnly]
- 你可以重写GenericAPIView 的任何方法
-
class AccountViewSet(viewsets.ModelViewSet): """ A simple ViewSet for viewing and editing the accounts associated with the user. """ serializer_class = AccountSerializer permission_classes = [IsAccountAdminOrReadOnly] def get_queryset(self): return self.request.user.accounts.all()
- ViewSet
- 仅可读的 ReadOnlyModelViewSet
- 继承自GenericAPIView ,它只提供给 read-only actions 、list() 、retrieve()
-
lass AccountViewSet(viewsets.ReadOnlyModelViewSet): """ A simple ViewSet for viewing accounts. """ queryset = Account.objects.all() serializer_class = AccountSerializer
- Custom ViewSet base classes
- 你可能需要类似ViewSet 但不需要全部的actions
- 创建一个 基础视图类 ,继承GenericViewSet 和Mixins提供create list retrieve 操作
from rest_framework import mixins class CreateListRetrieveViewSet(mixins.CreateModelMixin, mixins.ListModelMixin, mixins.RetrieveModelMixin, viewsets.GenericViewSet): """ A viewset that provides `retrieve`, `create`, and `list` actions. To use it, override the class and set the `.queryset` and `.serializer_class` attributes. """ pass
- Routers
- 使用SampleRouter
-
from rest_framework import routers router = routers.SimpleRouter() router.register(r'users', UserViewSet) router.register(r'accounts', AccountViewSet) urlpatterns = router.urls
- prefix 前缀 -必填
- viewset viewset 类名 --必填
- basename url 的别名, 如果未设置,则基名称将基于视图集的queryset属性自动生成
- 范例
URL pattern: ^users/$ Name: 'user-list' URL pattern: ^users/{pk}/$ Name: 'user-detail' URL pattern: ^accounts/$ Name: 'account-list' URL pattern: ^accounts/{pk}/$ Name: 'account-detail'
- 您不需要指定basename参数,但是如果您有一个定义了自定义get_queryset方法的视图集,则该视图集可能没有设置.queryset属性。 如果您尝试注册该视图集,则会看到如下错误:
- 使用 include
- 所有的路由都要追加到urlpatterns 里面
-
router = routers.SimpleRouter() router.register(r'users', UserViewSet) router.register(r'accounts', AccountViewSet) urlpatterns = [ url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), ] urlpatterns += router.urls
-
urlpatterns = [ url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), url(r'^', include(router.urls)), ]
-
urlpatterns = [ url(r'^forgot-password/$', ForgotPasswordFormView.as_view()), url(r'^api/', include((router.urls, 'app_name'), namespace='instance_name')), ]
- 如果用到了hyperlinked serializers,你可以确保 view_name填值正确,以确保能跳转到detail view
- view_name = 'app_name:user-detail'
- 路由到额外的方法,使用@action
-
from myapp.permissions import IsAdminOrIsSelf from rest_framework.decorators import action class UserViewSet(ModelViewSet): ... @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf]) def set_password(self, request, pk=None): ...
-
URL pattern: ^users/{pk}/set_password/$ URL name: 'user-set-password'
- 使用 url name 自定义路由
-
from myapp.permissions import IsAdminOrIsSelf from rest_framework.decorators import action class UserViewSet(ModelViewSet): ... @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf], url_path='change-password', url_name='change_password') def set_password(self, request, pk=None): ...
-
URL path: ^users/{pk}/change-password/$ URL name: 'user-change_password'
-
-
- Siimple Router
- 路由可包括标准动作
list
,create
,retrieve
,update
,partial_update
anddestroy
- 也可通过action 装饰,添加额外的方法
- 默认情况下SimpleRouter 后面会带一个斜杠,可以通过将Trailing_slash参数设置为False来修改此行为。
-
router = SimpleRouter(trailing_slash=False)
-
- 在视图中添加 lookup_field 和 lookup_valule_regex 限制查询的匹配方式
-
class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet): lookup_field = 'my_model_id' lookup_value_regex = '[0-9a-f]{32}'
-
- 路由可包括标准动作
- DefaultRouter
- 和SimpleRouter 类似,但是还包括了一个默认的API根视图,该视图返回一个响应,其中包含指向所有列表视图的超链接。 它还为可选的.json样式格式后缀生成路由。
-
router = DefaultRouter(trailing_slash=False)
- Custom Routers
- 对URL 结构有特定要求,可自定义路
- 继承现有路由 ,routes 属性用于模板化将映射到每个视图集的URL 模式
- Routes 为元组,参数有
- url :一个字符串,代表要路由的URL ,可能包含以下格式字符串
- {perfix} 用于这组路由的前缀
- {lookup} 用于单个实例匹配的查找字段
- {trailing_slash} 后面斜杠有无,默认为True ,带斜杠
- mapping:Http 方法名称到视图方法的映射
- name: 在反向调用中使用URL 的名称,可能包含以下格式字符串
- {basename} 用于创建的URL 名称的基础
- initkwargs:实例化视图时传递的所有其他参数的字典
- url :一个字符串,代表要路由的URL ,可能包含以下格式字符串
- Customizing dynamic Routes
- 优化 @action 装饰的路由,在.routes 列表中包括名为tuple 的DynamicRoute,
- 将detail 参数设置为适合的基于列表的路由和基于细节的路由
- url {url_path}
- name {basename} {url_name}
-
from rest_framework.routers import Route, DynamicRoute, SimpleRouter class CustomReadOnlyRouter(SimpleRouter): """ A router for read-only APIs, which doesn't use trailing slashes. """ routes = [ Route( url=r'^{prefix}$', mapping={'get': 'list'}, name='{basename}-list', detail=False, initkwargs={'suffix': 'List'} ), Route( url=r'^{prefix}/{lookup}$', mapping={'get': 'retrieve'}, name='{basename}-detail', detail=True, initkwargs={'suffix': 'Detail'} ), DynamicRoute( url=r'^{prefix}/{lookup}/{url_path}$', name='{basename}-{url_name}', detail=True, initkwargs={} ) ]
- 使用范例
class UserViewSet(viewsets.ReadOnlyModelViewSet): """ A viewset that provides the standard actions """ queryset = User.objects.all() serializer_class = UserSerializer lookup_field = 'username' @action(detail=True) def group_names(self, request, pk=None): """ Returns a list of all the group names that the given user belongs to. """ user = self.get_object() groups = user.groups.all() return Response([group.name for group in groups])
-
router = CustomReadOnlyRouter() router.register('users', UserViewSet) urlpatterns = router.urls
-
- 使用SampleRouter
- Pasers
- 访问request.data 时,Rest 框架 将检查传入请求头的Content_type 标头,并确定使用哪个解释器来解析请求的内容
- 在开发客户端应用程序时,确保在HTTP请求中发送数据时设置了 Content-Type 标头
- 如果未设置内容累心那个,则大多数客户端将默认使用“application/x-www-form--urlencoded”
- 如果要使用jQuery和ajax() 方法发送json编码的数据,则应包括ContentType:"application/json"
- 设置Parsers
- setting 里的
DEFAULT_PARSER_CLASSES将被用于全局
- 在View 里添加 parser_classes = [JSONPaser] 作用局部视图
- 使用装饰器
@parser_classes([JSONParser]) 作用视图函数
- setting 里的
- JsonParser
- media_type:
application/json
- media_type:
- FormParser
- Html form data request.data将使用数据的QueryDict填充。
-
.media_type:
application/x-www-form-urlencoded
- MultiPartParser
- 解析大部分表单,支持文件上传 这两个request.data都将填充QueryDict。
- 同时使用FormParser和MultiPartParser,以便完全支持HTML表单数据。
- .media_type:multipart / form-data
- FileUploadParser
- 解析原始文件上传的内容,request.data 属性将是一个字典,其中包含上传文件的单个键“文件
- 如果FileUploadParser 一起使用的视图是通过文件名URL 关键字参数调用的,则该参数将作为文件名
- 如果没有文件名关键字参数的情况下调用该文件,则客户端必须在Content-Disposition HTTP 标头中设置文件名
- 例如Content-Disposition:附件; filename = upload.jpg。
- 媒体类型: */*
- FileUploadParser用于可将文件作为原始数据请求上传的本机客户端。对于基于Web的上载,或具有分段上载支持的本机客户端,应改为使用MultiPartParser
- 由于此解析器的media_type匹配任何内容类型,因此FileUploadParser通常应该是API视图上设置的唯一解析器
# views.py class FileUploadView(views.APIView): parser_classes = [FileUploadParser] def put(self, request, filename, format=None): file_obj = request.data['file'] # ... # do some stuff with uploaded file # ... return Response(status=204) # urls.py urlpatterns = [ # ... url(r'^upload/(?P<filename>[^/]+)$', FileUploadView.as_view()) ]
- 个性化自定义解释器
- 重写BaseParser
- 实现
parse(self, stream, media_type, parser_context)
- stteam 关于流的对象,请求体
- media_type 可选的 ,Content-Type 比media_type 更具体,例如“ text / plain; charset = utf-8”。
- parser_context 可选的。 如果提供,则此参数将是一个字典,其中包含解析请求内容可能需要的任何其他上下文。默认情况下,它将包括以下键:view,request,args,kwargs。
- 以下是一个示例纯文本解析器,它将使用代表请求主体的字符串填充request.data属性。
-
class PlainTextParser(BaseParser): """ Plain text parser. """ media_type = 'text/plain' def parse(self, stream, media_type=None, parser_context=None): """ Simply return a string representing the body of the request. """ return stream.read()
- YAML
-
$ pip install djangorestframework-yaml
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': [ 'rest_framework_yaml.parsers.YAMLParser', ], 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework_yaml.renderers.YAMLRenderer', ], }
-
- XML
-
$ pip install djangorestframework-xml
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': [ 'rest_framework_xml.parsers.XMLParser', ], 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework_xml.renderers.XMLRenderer', ], }
-
- Renderers渲染器
- 视图的有效渲染器集始终定义为类列表。 进入视图后,REST框架将对传入的请求执行内容协商,并确定最合适的渲染器以满足该请求。
- 内容协商的基本过程涉及检查请求的Accept报头,以确定请求在响应中期望的媒体类型。
- URL上的格式后缀可以用于显式请求特定的表示形式。 例如,URL http://example.com/api/users_count.json可能是始终返回JSON数据的终结点
- 在setting 中设置全局
-
REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ] }
- 在APIView 中设置局部
renderer_classes = [JSONRenderer]
- if you're using the
@api_view
decorator with function based views.@api_view(['GET']) @renderer_classes([JSONRenderer]) def user_count_view(request, format=None): """ A view that returns the count of active users in JSON. """ user_count = User.objects.filter(active=True).count() content = {'user_count': user_count} return Response(content)
-
- 选择渲染器
- 如果客户端未指定其可以接受的表示形式,例如发送Accept:* / *标头,或根本不包含Accept标头,则REST框架将选择列表中的第一个渲染器以用于响应。
- 如果您的API提供JSON响应和HTML可浏览的API,则可能要将JSONRenderer设置为默认渲染器,以便将JSON响应发送给未指定Accept标头的客户端。
- 如果您的API包含可根据请求提供常规网页和API响应的视图,则您可以考虑将TemplateHTMLRenderer设置为默认渲染器,以便与发送破损接受标头的旧版浏览器完美配合
- JsonRender
- 使用utf8 编码格式将 数据转化成jason
- Note that the default style is to include unicode characters, and render the response using a compact style with no unnecessary whitespace:
-
{"unicode black star":"★","value":999}
- indent=4 缩进4
{ "unicode black star": "★", "value": 999 }
- 可以使用UNICODE_JSON和COMPACT_JSON设置键来更改默认的JSON编码样式。
-
media_type:
application/json
.format:
'json'
.charset:
None
-
- TemplateHTMLRenderer
- 使用Django的标准模板渲染,将数据渲染为HTML。
- 与其他渲染器不同,传递给Response的数据不需要序列化
- 在创建Response时包括template_name参数
- TemplateHTMLRenderer将使用response.data作为上下文字典创建一个RequestContext,并确定用于渲染上下文的模板名称。
- 模板名称由(按优先顺序)确定:
- 传递给响应的显式template_name参数。
在此类上设置的显式.template_name属性。
调用view.get_template_names()的返回结果。
- 传递给响应的显式template_name参数。
-
class UserDetail(generics.RetrieveAPIView): """ A view that returns a templated HTML representation of a given user. """ queryset = User.objects.all() renderer_classes = [TemplateHTMLRenderer] def get(self, request, *args, **kwargs): self.object = self.get_object() return Response({'user': self.object}, template_name='user_detail.html')
- 可以使用TemplateHTMLRenderer通过REST框架返回常规HTML页面,或者从单个端点返回HTML和API响应。
- 如果要构建使用TemplateHTMLRenderer和其他渲染器类一起使用的网站,则应考虑将TemplateHTMLRenderer列为renderer_classes列表中的第一类,这样即使对于发送格式不正确的ACCEPT:标头的浏览器,它也将被优先处理。
- StaticHTMALRenderer
- 一个简单的渲染器,仅返回预渲染的HTML。
- 与其他渲染器不同,传递给响应对象的数据应为代表要返回内容的字符串。
-
@api_view(['GET']) @renderer_classes([StaticHTMLRenderer]) def simple_html_view(request): data = '<html><body><h1>Hello, world</h1></body></html>' return Response(data)
- BrowsableAPIRenderer
- 将数据呈现为可浏览的API html
- 默认情况下将使用除BrowsableAPIRenderer 之外的最高优先级渲染器来渲染响应内容
- ,例如使用HTML作为默认返回格式,但在可浏览的API中使用JSON,则可以通过重写get_default_renderer()方法来实现
-
class CustomBrowsableAPIRenderer(BrowsableAPIRenderer): def get_default_renderer(self, view): return JSONRenderer()
- AdminRender
- 渲染成admin 的模式
- HtmlFormRenderer
- 将序列化程序返回的数据呈现为HTML形式。 此渲染器的输出不包含封闭的<form>标记,隐藏的CSRF输入或任何提交按钮。
不能直接使用此渲染器,而是可以通过将序列化器实例传递给render_form模板标签,而在模板中使用。-
{% load rest_framework %} <form action="/submit-report/" method="post"> {% csrf_token %} {% render_form serializer %} <input type="submit" value="Save" /> </form>
Serializers
- REST框架中的序列化器的工作方式与Django的Form和ModelForm类非常相似
- 序列化程序允许将诸如查询集和模型实例之类的复杂数据转换为原生Python数据类型,轻松地将其呈现为JSON,XML或其他内容类型。
- 提供了一个Serializer类,它为您提供了一种强大的通用方法来控制响应的输出,
- 还提供了ModelSerializer类,该类为创建处理模型实例和查询集的序列化器提供了有用的快捷方式
- 声明序列器
- 创建数据
from datetime import datetime class Comment: def __init__(self, email, content, created=None): self.email = email self.content = content self.created = created or datetime.now() comment = Comment(email='leila@example.com', content='foo bar')
- 创建序列器
-
from rest_framework import serializers class CommentSerializer(serializers.Serializer): email = serializers.EmailField() content = serializers.CharField(max_length=200) created = serializers.DateTimeField()
-
- 序列化数据
- 生成 python 格式
serializer = CommentSerializer(comment) serializer.data # {'email': 'leila@example.com', 'content': 'foo bar', 'created': '2016-01-27T15:17:10.375877'}
- 转化成json 字符串
-
from rest_framework.renderers import JSONRenderer json = JSONRenderer().render(serializer.data) json # b'{"email":"leila@example.com","content":"foo bar","created":"2016-01-27T15:17:10.375877"}'
-
- 生成 python 格式
- 反序列化数据
- 转化成python 原生数据类型
import io from rest_framework.parsers import JSONParser stream = io.BytesIO(json) data = JSONParser().parse(stream)
- 再转成经过验证的字典类型
serializer = CommentSerializer(data=data) serializer.is_valid() # True serializer.validated_data # {'content': 'foo bar', 'email': 'leila@example.com', 'created': datetime.datetime(2012, 08, 22, 16, 20, 09, 822243)}
- 转化成python 原生数据类型
- 创建数据
- 保存实例对象
- 如果我们希望能够基于经过验证的数据返回完整的对象实例,则需要实现.create()和.update()方法之一或两者
class CommentSerializer(serializers.Serializer): email = serializers.EmailField() content = serializers.CharField(max_length=200) created = serializers.DateTimeField() def create(self, validated_data): return Comment(**validated_data) def update(self, instance, validated_data): instance.email = validated_data.get('email', instance.email) instance.content = validated_data.get('content', instance.content) instance.created = validated_data.get('created', instance.created) return instance
- 如果您的对象实例与Django模型相对应,则还需要确保这些方法将对象保存到数据库中。 例如,如果Comment是Django模型,则方法可能如下所示:
def create(self, validated_data): return Comment.objects.create(**validated_data) def update(self, instance, validated_data): instance.email = validated_data.get('email', instance.email) instance.content = validated_data.get('content', instance.content) instance.created = validated_data.get('created', instance.created) instance.save() return instance
- 对数据进行反序列化时,我们可以基于验证的数据调用.save()以返回对象实例。
comment = serializer.save()
- 调用.save()将创建一个新实例,或者更新一个现有实例,具体取决于在实例化序列化程序类时是否传递了一个现有实例:
# .save() will create a new instance. serializer = CommentSerializer(data=data) # .save() will update the existing `comment` instance. serializer = CommentSerializer(comment, data=data)
- 您希望您的视图代码能够在保存实例时注入其他数据。 此附加数据可能包括诸如当前用户,当前时间或不属于请求数据一部分的任何其他信息。
- 您可以通过在调用.save()时包括其他关键字参数来实现。 例如:
- serializer.save(owner = request.user)
- 调用.create()或.update()时,任何其他关键字参数都将包含在validated_data参数中。
直接覆盖.save()。 - 可能会选择直接重写.save(),因为它更具可读性和意义。
class ContactForm(serializers.Serializer): email = serializers.EmailField() message = serializers.CharField() def save(self): email = self.validated_data['email'] message = self.validated_data['message'] send_email(from=email, message=message)
- 如果我们希望能够基于经过验证的数据返回完整的对象实例,则需要实现.create()和.update()方法之一或两者
- Validation
- 反序列化数据时,在尝试访问经过验证的数据或保存对象实例之前,始终需要调用is_valid()。 如果发生任何验证错误,则.errors属性将包含代表所得错误消息的字典
-
serializer = CommentSerializer(data={'email': 'foobar', 'content': 'baz'}) serializer.is_valid() # False serializer.errors # {'email': ['Enter a valid e-mail address.'], 'created': ['This field is required.']}
- .is_valid()方法采用一个可选的raise_exception标志,如果存在验证错误,它将导致引发serializers.ValidationError异常。
# Return a 400 response if the data was invalid. serializer.is_valid(raise_exception=True)
- validate_ <field_name>方法应返回经过验证的值或引发serializers.ValidationError。 例如:
from rest_framework import serializers class BlogPostSerializer(serializers.Serializer): title = serializers.CharField(max_length=100) content = serializers.CharField() def validate_title(self, value): """ Check that the blog post is about Django. """ if 'django' not in value.lower(): raise serializers.ValidationError("Blog post is not about Django") return value
- Object-level validation
-
from rest_framework import serializers class EventSerializer(serializers.Serializer): description = serializers.CharField(max_length=100) start = serializers.DateTimeField() finish = serializers.DateTimeField() def validate(self, data): """ Check that start is before finish. """ if data['start'] > data['finish']: raise serializers.ValidationError("finish must occur after start") return data
- 将要满足的条件当作一个函数传给需要序列的字段
def multiple_of_ten(value): if value % 10 != 0: raise serializers.ValidationError('Not a multiple of ten') class GameRecord(serializers.Serializer): score = IntegerField(validators=[multiple_of_ten]) ...
- 序列化程序类还可以包括可重复使用的验证器,这些验证器将应用于完整的字段数据集。 通过在内部Meta类上声明它们,可以包含这些验证器,如下所示:
class EventSerializer(serializers.Serializer): name = serializers.CharField() room_number = serializers.IntegerField(choices=[101, 102, 103, 201]) date = serializers.DateField() class Meta: # Each room only has one event per day. validators = [ UniqueTogetherValidator( queryset=Event.objects.all(), fields=['room_number', 'date'] ) ]
- 将初始对象或查询集传递给序列化程序实例时,该对象将以.instance的形式提供。 如果没有传递初始对象,则.instance属性将为None。
- 当将数据传递给序列化程序实例时,未修改的数据将以.initial_data的形式提供。 如果未传递data关键字参数,则.initial_data属性将不存在。
- 默认情况下,必须为所有必填字段传递序列化器值,否则序列化器会引发验证错误。 您可以使用partial参数以允许部分更新。
# Update `comment` with partial data serializer = CommentSerializer(comment, data={'content': 'foo bar'}, partial=True)
- 处理嵌套对象
- Serializer类本身是Field的一种,可用于表示一种对象类型嵌套在另一种对象类型中的关系。
class UserSerializer(serializers.Serializer): email = serializers.EmailField() username = serializers.CharField(max_length=100) class CommentSerializer(serializers.Serializer): user = UserSerializer() content = serializers.CharField(max_length=200) created = serializers.DateTimeField()
- 如果嵌套表示形式可以选择接受None值,则应将required = False标志传递给嵌套序列化器。
class CommentSerializer(serializers.Serializer): user = UserSerializer(required=False) # May be an anonymous user. content = serializers.CharField(max_length=200) created = serializers.DateTimeField()
- 如果嵌套表示形式可以选择接受多值,则应将many =True标志传递给嵌套序列化器。
class CommentSerializer(serializers.Serializer): user = UserSerializer(required=False) edits = EditItemSerializer(many=True) # A nested list of 'edit' items. content = serializers.CharField(max_length=200) created = serializers.DateTimeField()
- Serializer类本身是Field的一种,可用于表示一种对象类型嵌套在另一种对象类型中的关系。
- 当处理支持反序列化数据的嵌套表示形式时,嵌套对象的任何错误都将嵌套在嵌套对象的字段名称下。
serializer = CommentSerializer(data={'user': {'email': 'foobar', 'username': 'doe'}, 'content': 'baz'}) serializer.is_valid() # False serializer.errors # {'user': {'email': ['Enter a valid e-mail address.']}, 'created': ['This field is required.']}
- 为嵌套表示编写.create()方法
class UserSerializer(serializers.ModelSerializer): profile = ProfileSerializer() class Meta: model = User fields = ['username', 'email', 'profile'] def create(self, validated_data): profile_data = validated_data.pop('profile') user = User.objects.create(**validated_data) Profile.objects.create(user=user, **profile_data) return user
- 为嵌套表示编写.update()方法
def update(self, instance, validated_data): profile_data = validated_data.pop('profile') # Unless the application properly enforces that this field is # always set, the following could raise a `DoesNotExist`, which # would need to be handled. profile = instance.profile instance.username = validated_data.get('username', instance.username) instance.email = validated_data.get('email', instance.email) instance.save() profile.is_premium_member = profile_data.get( 'is_premium_member', profile.is_premium_member ) profile.has_support_contract = profile_data.get( 'has_support_contract', profile.has_support_contract ) profile.save() return instance
-
- 处理多类型对象
- 要序列化查询集或对象列表而不是单个对象实例,应在实例化序列化程序时传递many = True标志。 然后,您可以传递查询集或要序列化的对象列表。
queryset = Book.objects.all() serializer = BookSerializer(queryset, many=True) serializer.data # [ # {'id': 0, 'title': 'The electric kool-aid acid test', 'author': 'Tom Wolfe'}, # {'id': 1, 'title': 'If this is a man', 'author': 'Primo Levi'}, # {'id': 2, 'title': 'The wind-up bird chronicle', 'author': 'Haruki Murakami'} # ]
- 要序列化查询集或对象列表而不是单个对象实例,应在实例化序列化程序时传递many = True标志。 然后,您可以传递查询集或要序列化的对象列表。
- 包括额外的context
- 在某些情况下,除了要序列化的对象外,还需要向序列化器提供额外的上下文
- 一种常见的情况是,如果您使用的是包含超链接关系的序列化程序,则要求序列化程序有权访问当前请求,以便它可以正确生成完全合格的URL。
- 您可以在实例化序列化程序时通过传递上下文参数来提供任意其他上下文。 例如:
serializer = AccountSerializer(account, context={'request': request}) serializer.data # {'id': 6, 'owner': 'denvercoder9', 'created': datetime.datetime(2013, 2, 12, 09, 44, 56, 678870), 'details': 'http://example.com/accounts/6/details'}
- 通过访问self.context属性,可以在任何序列化程序字段逻辑(例如自定义.to_representation()方法)中使用上下文字典。
- ModelSerializer
- 与Django模型定义紧密映射的序列化程序类。
- ModelSerializer类提供了一个快捷方式,使您可以自动创建带有与Model字段相对应的字段的Serializer类。
- ModelSerializer类与常规Serializer类相同,除了:
- 它将根据模型自动为您生成一组字段。
- 它将自动为序列化器生成验证器,例如unique_together验证器。
- 它包括.create()和.update()的简单默认实现。
- 它将根据模型自动为您生成一组字段。
- 声明一个ModelSerializer看起来像这样:
class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'account_name', 'users', 'created']
- 默认情况下,该类上的所有模型字段都将映射到相应的序列化器字段。
- 任何关系(例如模型上的外键)都将映射到PrimaryKeyRelatedField。
- 默认情况下不包括反向关系,除非按照序列化器关系文档中的指定明确包含反向关系。
- 序列化程序类会生成有用的详细表示形式字符串,使您可以全面检查其字段的状态
- 这在使用ModelSerializers时非常有用,在ModelSerializers中您要确定要为您自动创建哪些字段和验证器集。
>>> from myapp.serializers import AccountSerializer >>> serializer = AccountSerializer() >>> print(repr(serializer)) AccountSerializer(): id = IntegerField(label='ID', read_only=True) name = CharField(allow_blank=True, max_length=100, required=False) owner = PrimaryKeyRelatedField(queryset=User.objects.all())
- 指定要包括的字段
- 如果只希望在模型序列化程序中使用默认字段的子集,则可以使用字段或排除选项,就像使用ModelForm一样。
- 使用fields属性显式设置应序列化的所有字段。当模型更改时,这将减少导致意外暴露数据的可能性。
class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'account_name', 'users', 'created']
- 包含全部属性
class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account fields = '__all__'
- 排除指定属性
class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account exclude = ['users']
- Specifying nested serialization 级联序列化
- 默认的ModelSerializer使用主键来建立关系,但您也可以使用depth选项轻松生成嵌套表示:
class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'account_name', 'users', 'created'] depth = 1
- depth选项应设置为整数值,该整数值指示在还原为平面表示形式之前应遍历的关系的深度。
- 默认的ModelSerializer使用主键来建立关系,但您也可以使用depth选项轻松生成嵌套表示:
- 添加额外的字段
- 您可以在ModelSerializer中添加额外的字段,也可以通过在类上声明字段来覆盖默认字段,就像对Serializer类一样。
class AccountSerializer(serializers.ModelSerializer): url = serializers.CharField(source='get_absolute_url', read_only=True) groups = serializers.PrimaryKeyRelatedField(many=True) class Meta: model = Account
- 您可以在ModelSerializer中添加额外的字段,也可以通过在类上声明字段来覆盖默认字段,就像对Serializer类一样。
- 指定只读字段
- 您可能希望将多个字段指定为只读。 您可以使用快捷方式Meta选项read_only_fields来代替使用read_only = True属性显式添加每个字段。
class AccountSerializer(serializers.ModelSerializer): class Meta: model = Account fields = ['id', 'account_name', 'users', 'created'] read_only_fields = ['account_name']
- 默认情况下,具有editable = False设置的模型字段和AutoField字段将被设置为只读,并且不需要将其添加到read_only_fields选项。
- 这方面的一个示例是与当前已认证用户的只读关系,该关系与另一个标识符一起为unique_together。 在这种情况下,您将这样声明用户字段:
user = serializers.PrimaryKeyRelatedField(read_only=True, default=serializers.CurrentUserDefault())
- 您可能希望将多个字段指定为只读。 您可以使用快捷方式Meta选项read_only_fields来代替使用read_only = True属性显式添加每个字段。
- 额外的关键字参数
- 还有一个快捷方式允许您使用extra_kwargs选项在字段上指定任意其他关键字参数。
- 与read_only_fields一样,这意味着您无需在序列化程序上显式声明该字段。
- 此选项是一个字典,将字段名称映射到关键字参数的字典。 例如:
-
class CreateUserSerializer(serializers.ModelSerializer): class Meta: model = User fields = ['email', 'username', 'password'] extra_kwargs = {'password': {'write_only': True}} def create(self, validated_data): user = User( email=validated_data['email'], username=validated_data['username'] ) user.set_password(validated_data['password']) user.save() return user
- Relational fields
- ModelSerializer的默认表示是使用相关实例的主键。
- 与Django模型定义紧密映射的序列化程序类。
HyperlinkedModelSerializer
- 和Modelserializer 类似 不同之处在于它使用超链接表示关系而不是主键。
- 默认情况下,序列化程序将包括url字段而不是主键字段。
- url字段将使用HyperlinkedIdentityField序列化器字段表示,并且模型上的任何关系都将使用HyperlinkedRelatedField序列化器字段表示。
- 您可以通过将主键添加到fields选项中来显式包括主键,例如:
class AccountSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Account fields = ['url', 'id', 'account_name', 'users', 'created']
- 绝对和相对URL
- 如果你序列化器包含当前的request ,将会生成绝对路径
http://api.example.com/accounts/1/
serializer = AccountSerializer(queryset, context={'request': request})
- 如果你想用相对路径
{'request': None}
- 如果你序列化器包含当前的request ,将会生成绝对路径
- 如何确定超链接视图
- 默认情况下,超链接应与匹配样式'{model_name} -detail'的视图名称相对应,并通过pk关键字参数查找实例。
- 您可以通过使用extra_kwargs设置中的view_name和lookup_field选项之一或全部来覆盖URL字段视图名称和查找字段,如下所示:
class AccountSerializer(serializers.HyperlinkedModelSerializer): class Meta: model = Account fields = ['account_url', 'account_name', 'users', 'created'] extra_kwargs = { 'url': {'view_name': 'accounts', 'lookup_field': 'account_name'}, 'users': {'lookup_field': 'username'} }
- 设置lookup_field
class AccountSerializer(serializers.HyperlinkedModelSerializer): url = serializers.HyperlinkedIdentityField( view_name='accounts', lookup_field='slug' ) users = serializers.HyperlinkedRelatedField( view_name='user-detail', lookup_field='username', many=True, read_only=True ) class Meta: model = Account fields = ['url', 'account_name', 'users', 'created']
- 默认情况下,超链接应与匹配样式'{model_name} -detail'的视图名称相对应,并通过pk关键字参数查找实例。
- ListSerializer
- ListSerializer类提供了一次序列化和验证多个对象的行为
- 通常不需要直接使用ListSerializer,而是在实例化序列化器时只需传递many = True即可。
- 实例化序列化程序并传递many = True时,将创建一个ListSerializer实例。 然后,序列化程序类成为父级ListSerializer的子级
Serializer Fields
- 序列化器字段处理原始值和内部数据类型之间的转换。 它们还处理验证输入值,以及从其父对象检索和设置值。
- 每个序列化器字段类构造函数都至少接受这些参数。 某些Field类采用其他特定于字段的参数,但应始终接受以下内容
- read_only 只读
- write_only 只写
- required 如果反序列化过程中未提供字段,通常会引发错误。 如果反序列化过程中不需要此字段,则设置为false,默认为True
- default 默认值 序列化实例时,如果实例中不存在对象属性或字典键,则将使用默认值,设置默认值意味着不需要该字段。 同时包含default和required关键字参数是无效的,并且会引发错误。
- allow_null 允许为空 如果没有显式默认值,将此参数设置为True将意味着序列化输出的默认值为null,但并不意味着输入反序列化的默认值。
- source 将用于填充字段的属性的名称。 可能是仅接受自变量的方法,例如URLField(source ='get_absolute_url'),或者可以使用点分符号遍历属性,例如EmailField(source ='user.email')。 当使用点符号序列化字段时,如果在属性遍历期间不存在任何对象或对象为空,则可能需要提供默认值。,值source ='*'具有特殊含义,用于表示应将整个对象传递给该字段。
- validators 验证器功能列表,应将其应用于传入字段输入,并且会引发验证错误或简单地返回。 验证器函数通常应引发serializers.ValidationError,
- error_message 一个字典,字段:错误消息
- lable 短文本字符串,可用作HTML表单字段或其他描述性元素中的字段名称。
- help_text 可用作在HTML表单字段或其他描述性元素中对该字段进行描述的文本字符串。
- initial 该值应用于预先填充HTML表单字段的值。 您可以将callable传递给它,就像处理任何常规Django Field一样
import datetime from rest_framework import serializers class ExampleSerializer(serializers.Serializer): day = serializers.DateField(initial=datetime.date.today)
- style 键值对字典,可用于控制渲染器应如何渲染字段。这里有两个例子是“ input_type”和“ base_template”:
# Use <input type="password"> for the input. password = serializers.CharField( style={'input_type': 'password'} ) # Use a radio input instead of a select input. color_channel = serializers.ChoiceField( choices=['red', 'green', 'blue'], style={'base_template': 'radio.html'} )
- Filed
- Boolean
- BooleanField
- NullBooleanField
- String fileds
- charField
- EmailFiled
- RegexField
- slugFiled
- URLField
- UUIDfIELD
- FilePathField
- IPAddressField
- Numeric Fields
- IntegerFiled
- FloatField
- DecimalField
- Date and Time
- DateTimeFiled
- DateField
- TimeField
- DurationField
- choise selection fields
- choiceFiled
- MultipleChoiceFiled
- File upload fields
- FieldField
- ImageField
- Composite fields
- ListField
- DictField
- HStoreField
- JSONField
- Miscellaneous fields
- ReadOnlyField
- HiddenField
- ModelField
- SerializerMethodField
- Custom fields
- Boolean
Serializer relations
- 关系字段用于表示模型关系
- 它们可以应用于ForeignKey,ManyToManyField和OneToOneField关系,以及反向关系和自定义关系,如GenericForeignKey。
-
class Album(models.Model): album_name = models.CharField(max_length=100) artist = models.CharField(max_length=100) class Track(models.Model): album = models.ForeignKey(Album, related_name='tracks', on_delete=models.CASCADE) order = models.IntegerField() title = models.CharField(max_length=100) duration = models.IntegerField() class Meta: unique_together = ['album', 'order'] ordering = ['order'] def __str__(self): return '%d: %s' % (self.order, self.title)
- StringRelatedField
- StringRelatedField可以使用其__str__方法来表示关系的目标。,反向引用时,仅返回 __str__ 中的 fileds
class AlbumSerializer(serializers.ModelSerializer): tracks = serializers.StringRelatedField(many=True) class Meta: model = Album fields = ['album_name', 'artist', 'tracks']
-
{ 'album_name': 'Things We Lost In The Fire', 'artist': 'Low', 'tracks': [ '1: Sunflower', '2: Whitetail', '3: Dinosaur Act', ... ] }
- 参数 many 一对多模型many =True
- StringRelatedField可以使用其__str__方法来表示关系的目标。,反向引用时,仅返回 __str__ 中的 fileds
- PrimaryKeyRelatedField
- 可以用于使用其主键表示关系的目标。
class AlbumSerializer(serializers.ModelSerializer): tracks = serializers.PrimaryKeyRelatedField(many=True, read_only=True) class Meta: model = Album fields = ['album_name', 'artist', 'tracks']
-
{ 'album_name': 'Undun', 'artist': 'The Roots', 'tracks': [ 89, 90, 91, ... ] }
- 参数
- queryset 验证字段输入时用于模型实例查找的查询集。 关系必须要么显式设置一个查询集,要么设置read_only = True。
- many 如果应用于多对多关系,则应将此参数设置为True。
- all_null allow_null-如果设置为True,则该字段将接受None值或可为空的关系的空字符串。 默认为False
- pk_field pk_field-设置为一个字段以控制主键值的序列化/反序列化。 例如,pk_field = UUIDField(format ='hex')会将UUID主键序列化为其紧凑的十六进制表示形式。
- 可以用于使用其主键表示关系的目标。
- HyperlinkedRelatedFiled
- 通过link 展现关系
-
class AlbumSerializer(serializers.ModelSerializer): tracks = serializers.HyperlinkedRelatedField( many=True, read_only=True, view_name='track-detail' ) class Meta: model = Album fields = ['album_name', 'artist', 'tracks']
-
{ 'album_name': 'Graceland', 'artist': 'Paul Simon', 'tracks': [ 'http://www.example.com/api/tracks/45/', 'http://www.example.com/api/tracks/46/', 'http://www.example.com/api/tracks/47/', ... ] }
- 参数
- view_name 用作关系目标的视图名称。如果您使用的是标准路由器类,则该字符串将是格式为<modelname> -detail的字符串
- queryset queryset-验证字段输入时用于模型实例查找的查询集。关系必须要么显式设置一个查询集,要么设置read_only = True。
- many 用于多对多关系,则应将此参数设置为True。
- allow_null allow_null-如果设置为True,则该字段将接受None值或可为空的关系的空字符串。默认为False。
- lookup_field 目标上应用于查找的字段。应对应于引用视图上的URL关键字参数。默认值为“ pk”。
- lookup_url_kwarg URL conf中与查找字段相对应的关键字参数的名称。默认使用与lookup_field相同的值。
- format 如果使用格式后缀,则超链接字段将为目标使用相同的格式后缀,除非使用format参数将其覆盖。
- SlugRelatedField
- 可用于使用目标上的字段表示关系的目标。
class AlbumSerializer(serializers.ModelSerializer): tracks = serializers.SlugRelatedField( many=True, read_only=True, slug_field='title' ) class Meta: model = Album fields = ['album_name', 'artist', 'tracks']
-
{ 'album_name': 'Dear John', 'artist': 'Loney Dear', 'tracks': [ 'Airport Surroundings', 'Everything Turns to You', 'I Was Only Going Out', ... ] }
- 参数
- slug_field 目标上用于表示它的字段。 这应该是一个唯一标识任何给定实例的字段。 例如,用户名
- queryset
- many
- allow_null
- 可用于使用目标上的字段表示关系的目标。
- HyperlinkedIdentityFiled
- 该字段可以用作身份关系,例如HyperlinkedModelSerializer上的“ url”字段。 它也可以用于对象的属性。 例如,以下序列化器:
-
class AlbumSerializer(serializers.HyperlinkedModelSerializer): track_listing = serializers.HyperlinkedIdentityField(view_name='track-list') class Meta: model = Album fields = ['album_name', 'artist', 'track_listing']
{ 'album_name': 'The Eraser', 'artist': 'Thom Yorke', 'track_listing': 'http://www.example.com/api/track_list/12/', }
- 参数
- view_name 用作关系目标的视图名称
- lookup_field
- lookup_url_kwargs URL conf中与查找字段相对应的关键字参数的名称。 默认使用与lookup_field相同的值。
- format 如果使用格式后缀,则超链接字段将为目标使用相同的格式后缀,除非使用format参数将其覆盖。
- Nested_relationships
- 与先前讨论的对另一实体的引用相反,所引用的实体也可以嵌入或嵌套在引用该实体的对象的表示中。 这样的嵌套关系可以通过使用序列化器作为字段来表达。
- 如果该字段用于表示一对多关系,则应在序列化器字段中添加many = True标志。
class TrackSerializer(serializers.ModelSerializer): class Meta: model = Track fields = ['order', 'title', 'duration'] class AlbumSerializer(serializers.ModelSerializer): tracks = TrackSerializer(many=True, read_only=True) class Meta: model = Album fields = ['album_name', 'artist', 'tracks']
-
'album_name': 'The Grey Album', 'artist': 'Danger Mouse', 'tracks': [ {'order': 1, 'title': 'Public Service Announcement', 'duration': 245}, {'order': 2, 'title': 'What More Can I Say', 'duration': 264}, {'order': 3, 'title': 'Encore', 'duration': 159}, ... ], }
- 与先前讨论的对另一实体的引用相反,所引用的实体也可以嵌入或嵌套在引用该实体的对象的表示中。 这样的嵌套关系可以通过使用序列化器作为字段来表达。
- Writable nested serializers
- 默认情况下,嵌套序列化器是只读的。
- 如果要支持对嵌套序列化器字段的写操作,则需要创建create()和/或update()方法,以明确指定应如何保存子关系。
class TrackSerializer(serializers.ModelSerializer): class Meta: model = Track fields = ['order', 'title', 'duration'] class AlbumSerializer(serializers.ModelSerializer): tracks = TrackSerializer(many=True) class Meta: model = Album fields = ['album_name', 'artist', 'tracks'] def create(self, validated_data): tracks_data = validated_data.pop('tracks') album = Album.objects.create(**validated_data) for track_data in tracks_data: Track.objects.create(album=album, **track_data) return album >>> data = { 'album_name': 'The Grey Album', 'artist': 'Danger Mouse', 'tracks': [ {'order': 1, 'title': 'Public Service Announcement', 'duration': 245}, {'order': 2, 'title': 'What More Can I Say', 'duration': 264}, {'order': 3, 'title': 'Encore', 'duration': 159}, ], } >>> serializer = AlbumSerializer(data=data) >>> serializer.is_valid() True >>> serializer.save() <Album: Album object>
Validation
- Django REST框架序列化程序中的验证与Django的ModelForm类中的验证工作方式略有不同。
- 使用ModelForm,验证部分在表单上执行,部分在模型实例上执行。使用REST框架,验证完全在序列化程序类上执行。由于以下原因,这是有利的:
- 它引入了适当的关注点分离,使您的代码行为更加明显
- 在使用快捷方式ModelSerializer类和使用显式Serializer类之间进行切换很容易。
- 用于ModelSerializer的任何验证行为都易于复制
- 打印序列化程序实例的代表将准确显示其适用的验证规则。在模型实例上没有调用任何额外的隐藏验证行为。
class CustomerReportRecord(models.Model): time_raised = models.DateTimeField(default=timezone.now, editable=False) reference = models.CharField(unique=True, max_length=20) description = models.TextField()
-
class CustomerReportSerializer(serializers.ModelSerializer): class Meta: model = CustomerReportRecord
-
>>> from project.example.serializers import CustomerReportSerializer >>> serializer = CustomerReportSerializer() >>> print(repr(serializer)) CustomerReportSerializer(): id = IntegerField(label='ID', read_only=True) time_raised = DateTimeField(read_only=True) reference = CharField(max_length=20, validators=[<UniqueValidator(queryset=CustomerReportRecord.objects.all())>]) description = CharField(style={'type': 'textarea'})
Unique Validator - 参数 queryset message lookup
-
from rest_framework.validators import UniqueValidator slug = SlugField( max_length=100, validators=[UniqueValidator(queryset=BlogPost.objects.all())] )
- queryset fields message
- UniqueTogetherValidator类始终强加一个隐式约束,该约束应用于它的所有字段始终按要求处理。 具有默认值的字段是一个例外,因为即使从用户输入中省略,它们也始终提供一个值。
-
from rest_framework.validators import UniqueTogetherValidator class ExampleSerializer(serializers.Serializer): # ... class Meta: # ToDo items belong to a parent list, and have an ordering defined # by the 'position' field. No two items in a given list may share # the same position. validators = [ UniqueTogetherValidator( queryset=ToDoItem.objects.all(), fields=['list', 'position'] ) ]
-
- 其他以后再看吧,省略
Authrntication
- 身份验证是将传入请求与一组标识凭据(例如,请求来自的用户或与其进行签名的令牌)相关联的机制。
- 然后,权限和限制策略可以使用这些凭据来确定是否应允许该请求。
- REST框架提供了许多开箱即用的身份验证方案,并且还允许您实现自定义方案。
- 身份验证始终在视图的最开始处,在进行权限检查和限制检查之前以及在允许任何其他代码进行之前运行。
- 通常将request.user属性设置为contrib.auth包的User类的实例。
- request.auth属性用于任何其他身份验证信息,例如,它可用于表示签署请求的身份验证令牌。
- 身份验证方案始终定义为类列表。 REST框架将尝试对列表中的每个类进行身份验证,并将使用成功进行身份验证的第一个类的返回值设置request.user和request.auth。
- 如果没有任何类进行身份验证,则request.user将设置为django.contrib.auth.models.AnonymousUser的实例,而request.auth将设置为None。
- 可以使用UNAUTHENTICATED_USER和UNAUTHENTICATED_TOKEN设置来修改未认证请求的request.user和request.auth的值。
- 在Setting 中设置全局认证方式
-
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.BasicAuthentication', 'rest_framework.authentication.SessionAuthentication', ] }
-
- 在APIView 中设置局部视图有效的 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': unicode(request.user), # `django.contrib.auth.User` instance. 'auth': unicode(request.auth), # None } return Response(content)
- 如果有使用@api_view 装饰 ,也可使用@authentication_calsses([SessionAuthrntication,BasicAuthentication])
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': unicode(request.user), # `django.contrib.auth.User` instance. 'auth': unicode(request.auth), # None } return Response(content)
- 状态码
- 401 Unauthorized 未授权 HTTP 401响应必须始终包含WWW-Authenticate标头,该标头指示客户端如何进行身份验证
- 403 Forbidden permission deny 权限被拒绝,HTTP 403响应不包含WWW-Authenticate标头。
- BasicAuthentication
- 认证成功后 request.user 表示一个用户实例
- request.auth 为 None
- TokenAuthrntication
- install_apps
'rest_framework.authtoken'
- migrate 生成用户表
-
from rest_framework.authtoken.models import Token token = Token.objects.create(user=...) print(token.key)
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
WWW-Authenticate: Token
- 如果你希望每个登录的用户都自动生成一个token,只需要捕获 post_save 信号
from django.conf import settings from django.db.models.signals import post_save from django.dispatch import receiver from rest_framework.authtoken.models import Token @receiver(post_save, sender=settings.AUTH_USER_MODEL) def create_auth_token(sender, instance=None, created=False, **kwargs): if created: Token.objects.create(user=instance)
- 使用TokenAuthentication时,您可能希望为客户端提供一种机制,以给定用户名和密码来获得令牌。
- REST框架提供了一个内置视图来提供此行为。 要使用它,请将acquire_auth_token视图添加到您的URLconf中:
from rest_framework.authtoken import views urlpatterns += [ url(r'^api-token-auth/', views.obtain_auth_token) ]
- 默认的gain_auth_token视图明确使用JSON请求和响应,而不是在设置中使用默认的渲染器和解析器类。
- 如果需要定制版本的get_auth_token视图,则可以通过将ObtainAuthToken视图类子类化,然后在url conf中使用它来实现
from rest_framework.authtoken.views import ObtainAuthToken from rest_framework.authtoken.models import Token from rest_framework.response import Response class CustomAuthToken(ObtainAuthToken): def post(self, request, *args, **kwargs): serializer = self.serializer_class(data=request.data, context={'request': request}) serializer.is_valid(raise_exception=True) user = serializer.validated_data['user'] token, created = Token.objects.get_or_create(user=user) return Response({ 'token': token.key, 'user_id': user.pk, 'email': user.email })
urlpatterns += [ url(r'^api-token-auth/', CustomAuthToken.as_view()) ]
- Admin
- 也可以通过管理界面手动创建令牌。 如果您使用的是庞大的用户群,我们建议您对TokenAdmin类进行补丁修补,以根据需要对其进行自定义,更具体地说,是将用户字段声明为raw_field。
from rest_framework.authtoken.admin import TokenAdmin TokenAdmin.raw_id_fields = ['user']
./manage.py drf_create_token <username>
- 也可以通过管理界面手动创建令牌。 如果您使用的是庞大的用户群,我们建议您对TokenAdmin类进行补丁修补,以根据需要对其进行自定义,更具体地说,是将用户字段声明为raw_field。
- SessionAuthentication
- RemoteUserAuthentication
- Custome Authentication 自定义认证类
- 实例化BaseAuthentication并重写.authenticate(self,request)方法。
- 如果身份验证成功,则该方法应返回(user,auth)的二元组,否则返回None。
- 您可能不想从.authenticate()方法引发AuthenticationFailed异常,而不是返回None。
- 如果未尝试认证,则返回None。还在使用的任何其他身份验证方案仍将被检查
- 如果尝试进行身份验证但失败,则引发AuthenticationFailed异常。不管是否进行任何权限检查,并且不检查任何其他身份验证方案,都将立即返回错误响应。
- 您也可以覆盖.authenticate_header(self,request)方法。如果实现,它将返回一个字符串,该字符串将用作HTTP 401未经授权的响应中WWW-Authenticate标头的值。
- 果未覆盖.authenticate_header()方法,则当未认证的请求被拒绝访问时,认证方案将返回HTTP 403 Forbidden响应。
- 示例将对名为“ X-USERNAME”的自定义请求标头中的用户名指定的用户身份进行身份验证。
from django.contrib.auth.models import User from rest_framework import authentication from rest_framework import exceptions class ExampleAuthentication(authentication.BaseAuthentication): def authenticate(self, request): username = request.META.get('HTTP_X_USERNAME') if not username: return None try: user = User.objects.get(username=username) except User.DoesNotExist: raise exceptions.AuthenticationFailed('No such user') return (user, None)
- 其他认证插件,省略
- install_apps
Permissions
- 权限与身份认证一起确定请求是否被允许
- 权限检查始终在视图的最开始处运行,然后再允许执行其他任何代码。 权限检查通常将使用request.user和request.auth属性中的身份验证信息来确定是否应允许传入的请求。
- 最简单的许可方式是允许访问任何经过身份验证的用户,并拒绝访问任何未经身份验证的用户。 这对应于REST框架中的IsAuthenticated类。
- 稍微不太严格的权限样式将是允许对经过身份验证的用户进行完全访问,但允许对未经身份验证的用户进行只读访问。 这对应于REST框架中的IsAuthenticatedOrReadOnly类。
- 在运行视图主体之前,将检查列表中的每个权限。如果任何权限检查失败,则将引发exceptions.PermissionDenied或exceptions.NotAuthenticated异常,并且视图主体将不运行
- 当权限检查失败时,将根据以下规则返回“ 403禁止访问”或“ 401未经授权”响应:
- 该请求已成功通过身份验证,但权限被拒绝。 —将返回HTTP 403禁止响应
- REST框架权限还支持对象级权限。 对象级别权限用于确定是否应允许用户对特定对象执行操作,该对象通常是模型实例。
- 调用.get_object()时,对象级别权限由REST框架的通用视图运行。 与视图级别权限一样,如果不允许用户对给定对象执行操作,将引发exceptions.PermissionDenied异常。
-
def get_object(self): obj = get_object_or_404(self.get_queryset(), pk=self.kwargs["pk"]) self.check_object_permissions(self.request, obj) return obj
- 设置权限策略
-
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ] }
-
'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ]
- 在视图中使用permission_classes
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 装饰器,则也可用class 装饰
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)
- 当您通过class属性或装饰器设置新的权限类时,您是在告诉视图忽略settings.py文件上设置的默认列表。
- 如果它们继承自rest_framework.permissions.BasePermission,则可以使用标准Python按位运算符来组合权限。 例如,可以编写IsAuthenticatedOrReadOnly:
- it supports & (and), | (or) and ~ (not).
-
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)
-
- AllowAny 允许所有
- IsAuthenticated 已登录
- IsAdminUser
- IsAuthenticatedOrReadOny
- 将允许经过身份验证的用户执行任何请求。
- 仅当请求方法是“安全”方法之一时,才允许对未授权用户的请求; GET,HEAD或OPTIONS。
- DjangoModelPermissions
- 该权限类与Django的标准django.contrib.auth模型权限相关
- 此权限只能应用于设置了.queryset属性的视图
- 仅当用户通过身份验证并分配了相关的模型权限时,才授予授权。
- 该权限类与Django的标准django.contrib.auth模型权限相关
- DjangoModelPermissionsOrAnonReadOnly 与DjangoModelPermissions类似,但也允许未经身份验证的用户对API具有只读访问权限。
- DjangoObjectPermissions
- Custom permissions
- 继承 BasePermission
- 重写 has_permission(self,request,view) return True or False
- 重写 has_object_permission(self,request,view,obj) return
from rest_framework import permissions class BlacklistPermission(permissions.BasePermission): """ Global permission check for blacklisted IPs. """ def has_permission(self, request, view): ip_addr = request.META['REMOTE_ADDR'] blacklisted = Blacklist.objects.filter(ip_addr=ip_addr).exists() return not blacklisted
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
- 第三方包
- DRF-Access Policy 访问策略包提供了一种在声明性策略类中定义复杂访问规则的方法,该策略类附加到视图集或基于函数的视图。 这些策略以JSON格式定义,格式类似于AWS的身份和访问管理策略。
- Composed Permissions 组合权限包提供了一种使用小型且可重用的组件定义复杂和多深度(使用逻辑运算符)权限对象的简单方法。
- REST Condition REST条件包是用于以简单便捷的方式构建复杂权限的另一个扩展。 该扩展允许您将权限与逻辑运算符结合在一起。
- Django Rest Framework Roles 使在多种类型的用户上参数化API变得更加容易。
- Django RESTFramework API Key Django REST Framework API密钥包提供了权限类,模型和帮助程序,可将API密钥授权添加到您的API。 它可用于授权没有用户帐户的内部或第三方后端和服务(即计算机)。 API密钥使用Django的密码哈希基础结构安全地存储,并且可以随时在Django管理员中查看,编辑和吊销它们。
- Django Rest Framework Role Filters 提供用户角色的简单过滤
Catching
- Django提供了method_decorator来将装饰器与基于类的视图一起使用。
- 可以与其他缓存装饰器(例如cache_page和variant_on_cookie)一起使用。
from django.utils.decorators import method_decorator from django.views.decorators.cache import cache_page from django.views.decorators.vary import vary_on_cookie from rest_framework.response import Response from rest_framework.views import APIView from rest_framework import viewsets class UserViewSet(viewsets.ViewSet): # Cache requested url for each user for 2 hours @method_decorator(cache_page(60*60*2)) @method_decorator(vary_on_cookie) def list(self, request, format=None): content = { 'user_feed': request.user.get_user_feed() } return Response(content) class PostView(APIView): # Cache page for the requested url @method_decorator(cache_page(60*60*2)) def get(self, request, format=None): content = { 'title': 'Post title', 'body': 'Post content' } return Response(content)
Throttling
- 全局配置
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle' ], 'DEFAULT_THROTTLE_RATES': { 'anon': '100/day', 'user': '1000/day' } }
- APIView 中设置 throttle_classes
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)
- 客户端认证
- X-Forwarded-For HTTP标头和REMOTE_ADDR WSGI变量用于唯一地标识要限制的客户端IP地址。
- 果存在X-Forwarded-For标头,则将使用它,否则将使用WSGI环境中REMOTE_ADDR变量的值
- 使用缓存
- REST框架提供的节流类使用Django的缓存后端
- AnonRateThrottle 对未登录用户有效,使用IP 限流
- UserRateThrottle 对登录用户有效,使用user的ID 限流
- 自定义限流
class BurstRateThrottle(UserRateThrottle): scope = 'burst' class SustainedRateThrottle(UserRateThrottle): scope = 'sustained'
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'example.throttles.BurstRateThrottle', 'example.throttles.SustainedRateThrottle' ], 'DEFAULT_THROTTLE_RATES': { 'burst': '60/min', 'sustained': '1000/day' } }
- ScopedRateThrottle
- 可用于限制对API特定部分的访问。 仅当所访问的视图包含.throttle_scope属性时,才会应用此油门。
- 然后,通过将请求的“范围”与唯一的用户ID或IP地址串联起来,即可形成唯一的限制键。
- 允许的请求速率由DEFAULT_THROTTLE_RATES设置使用请求“范围”中的键确定。
class ContactListView(APIView): throttle_scope = 'contacts' ... class ContactDetailView(APIView): throttle_scope = 'contacts' ... class UploadView(APIView): throttle_scope = 'uploads' ...
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': [ 'rest_framework.throttling.ScopedRateThrottle', ], 'DEFAULT_THROTTLE_RATES': { 'contacts': '1000/day', 'uploads': '20/day' } }
- Custom throttles
- 继承
BaseThrottle ,实现
.allow_request(self, request, view), true or False
- 以下是速率调节的示例,它将在每10个请求中随机调节1。
import random class RandomRateThrottle(throttling.BaseThrottle): def allow_request(self, request, view): return random.randint(1, 10) != 1
- 继承
Filtering
- REST框架的通用列表视图的默认行为是返回模型管理器的整个查询集
- 筛选GenericAPIView子类的任何视图的查询集的最简单方法是覆盖.get_queryset()方法。
- 通过覆盖此方法,您可以通过多种不同方式自定义视图返回的查询集。
- Filtering aginst the current user
- 仅返回当前用户的信息 ,使用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)
- Filtering against the URL
- 根据URL 中的参数过滤
-
url('^purchases/(?P<username>.+)/$', PurchaseList.as_view()),
-
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)
- Filtering against query parameter
- 根据url中的查询参数确定初始查询集。
- 我们可以覆盖.get_queryset()来处理诸如http://example.com/api/purchases?username=denvercoder9之类的URL,仅在URL中包含username参数时才过滤查询集:
-
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', None) if username is not None: queryset = queryset.filter(purchaser__username=username) return queryset
- Generic Filtering
- Setting filter backens
-
REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'] }
-
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]
-
- Filtering and object lookups
- Overriding the initial queryset
- 同时使用重写queryset 和 过滤class
class PurchasedProductsList(generics.ListAPIView): """ Return a list of all the products that the authenticated user has ever purchased, with optional filtering. """ model = Product serializer_class = ProductSerializer filterset_class = ProductFilter def get_queryset(self): user = self.request.user return user.purchase_set.all()
- 同时使用重写queryset 和 过滤class
- DjangoFilterBackend
- django-filter库包含DjangoFilterBackend类,该类支持针对REST框架的高度可自定义的字段过滤。
- 要使用DjangoFilterBackend,请先安装django-filter。 然后将django_filters添加到Django的INSTALLED_APPS
-
pip install django-filter
-
REST_FRAMEWORK = { 'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend'] }
-
from django_filters.rest_framework import DjangoFilterBackend class UserListView(generics.ListAPIView): ... filter_backends = [DjangoFilterBackend]
class ProductList(generics.ListAPIView): queryset = Product.objects.all() serializer_class = ProductSerializer filter_backends = [DjangoFilterBackend] filterset_fields = ['category', 'in_stock']
http://example.com/api/products?category=clothing&in_stock=True
- SerchFilter
-
from rest_framework import filters class UserListView(generics.ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer filter_backends = [filters.SearchFilter] search_fields = ['username', 'email']
http://example.com/api/users?search=russell
- 外键 您还可以使用查找API双下划线表示法在ForeignKey或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']
- '^'开始搜索
-
- OderingFilter
-
http://example.com/api/users?ordering=username
-
http://example.com/api/users?ordering=-username
-
http://example.com/api/users?ordering=account,username
-
class UserListView(generics.ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer filter_backends = [filters.OrderingFilter] ordering_fields = ['username', 'email']
- 如果您确信该视图使用的查询集不包含任何敏感数据,则还可以使用特殊值'__all__'来明确指定一个视图应允许对任何模型字段或查询集集合进行排序。
class BookingsListView(generics.ListAPIView): queryset = Booking.objects.all() serializer_class = BookingSerializer filter_backends = [filters.OrderingFilter] ordering_fields = '__all__'
-
- Specifying a default ordering
- 您可以通过在初始查询集上设置order_by来控制此操作,但是使用视图上的ordering参数可以指定顺序,然后将其作为上下文自动传递到呈现的模板
-
class UserListView(generics.ListAPIView): queryset = User.objects.all() serializer_class = UserSerializer filter_backends = [filters.OrderingFilter] ordering_fields = ['username', 'email'] ordering = ['username']
Pagination
- 使用generic views 或者viewsets时,会自动调用分页器,可以通过将分页类设置为None 来关闭分页
- 使用普通的APIView 需要自己调用分页API 以确保返回分页响应
- 需要同时设置分页类和应使用的页面大小。 默认情况下,DEFAULT_PAGINATION_CLASS和PAGE_SIZE均为“无”。
- 设置分页Style
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 'PAGE_SIZE': 100 }
- 还可以根据每个视图,设置 class
- 修改分页器的style
- 如果要修改分页样式的特定方面,则需要覆盖其中一个分页类,并设置要更改的属性。
-
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
class BillingRecordsView(generics.ListAPIView): queryset = Billing.objects.all() serializer_class = BillingRecordsSerializer pagination_class = LargeResultsSetPagination
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination' }
- PageNumberPagination
-
GET 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": [ … ] }
- setting
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100 }
-
在GenerivAPIView 的子类中都有 pagination_class
- PageNumberPagination 包括一系列的style 属性值,可以被重写
- django_paginator_class ,默认为django.core.paginator.Paginator
- page_size 如果有设置,则覆盖PAGE_SIZE,否则使用seting的PAGE_SIZE
- page_query_param 一个字符串值,指示用于分页控件的查询参数的名称。
- page_size_query_param 如果设置,则是一个字符串值,指示允许客户端基于每个请求设置页面大小的查询参数的名称。 默认为无,表示客户端可能无法控制请求的页面大小。一页多少数据
- max_page_size 如果设置,则这是一个数字值,指示请求的最大允许页面大小。 仅当还设置了page_size_query_param时,此属性才有效。
- last_page_strings 字符串值的列表或元组,指示可以与page_query_param一起使用以请求集合中的最后一页的值。 默认为('last',)
- template 在可浏览的API中呈现分页控件时要使用的模板的名称。 可以重写以修改呈现样式,或设置为“无”以完全禁用HTML分页控件。 默认为“ rest_framework / pagination / numbers.html”
-
- LimitOffsetPagination
- 此分页样式反映了查找多个数据库记录时使用的语法。 客户端同时包含“限制”和“偏移”查询参数。 该限制表示要返回的最大项目数,并等于其他样式的page_size。 偏移量指示查询相对于未分页项的完整集合的开始位置。
-
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": [ … ] }
- 其他分页省略
Verisioning
- API版本控制使您可以更改不同客户端之间的行为。 REST框架提供了许多不同的版本控制方案。
- 版本控制由传入的客户端请求确定,并且可以基于请求URL或基于请求标头。
- 启用API版本控制后,request.version属性将包含一个字符串,该字符串与传入的客户端请求中请求的版本相对应。
- 默认情况下,不启用版本控制,并且request.version将始终返回None。
def get_serializer_class(self): if self.request.version == 'v1': return AccountSerializerVersion1 return AccountSerializer
省略
Content Negotiation
- Determing the accepted rendered 确定可接受的渲染器
- EST框架使用一种简单的内容协商样式,根据可用的渲染器,每个渲染器的优先级以及客户端的Accept:标头,确定应将哪种媒体类型返回给客户端。
- 使用的样式部分是客户端驱动的,部分是服务器驱动的。
- 较具体的媒体类型优先于较不具体的媒体类型。
- 如果多种媒体类型具有相同的特异性,则根据为给定视图配置的渲染器的顺序来优先考虑。
application/json; indent=4, application/json, application/yaml, text/html, */*
优先级为
application/json; indent=4 application/json, application/yaml and text/html */*
- 如果请求的视图仅配置了YAML和HTML渲染器,则REST框架将选择在renderer_classes列表或DEFAULT_RENDERER_CLASSES设置中首先列出的渲染器。
- Custom content negotiation
- 要实现自定义内容协商方案,请覆盖BaseContentNegotiation。
- EST框架的内容协商类既处理请求的适当解析器的选择,也处理响应的呈现器的选择,因此您应同时实现.select_parser(request,parsers)和.select_renderer(request,renderers,format_suffix)方法。
- select_parser()方法应从可用解析器列表中返回解析器实例之一,如果没有解析器可以处理传入的请求,则返回None。
- select_renderer()方法应返回一个二元组(渲染器实例,媒体类型),或引发NotAcceptable异常。
from rest_framework.negotiation import BaseContentNegotiation class IgnoreClientContentNegotiation(BaseContentNegotiation): def select_parser(self, request, parsers): """ Select the first parser in the `.parser_classes` list. """ return parsers[0] def select_renderer(self, request, renderers, format_suffix): """ Select the first renderer in the `.renderer_classes` list. """ return (renderers[0], renderers[0].media_type)
- 可以使用DEFAULT_CONTENT_NEGOTIATION_CLASS设置在全局范围内设置默认的内容协商类别
EST_FRAMEWORK = { 'DEFAULT_CONTENT_NEGOTIATION_CLASS': 'myapp.negotiation.IgnoreClientContentNegotiation', }
-
from myapp.negotiation import IgnoreClientContentNegotiation from rest_framework.response import Response from rest_framework.views import APIView class NoNegotiationView(APIView): """ An example view that does not perform content negotiation. """ content_negotiation_class = IgnoreClientContentNegotiation def get(self, request, format=None): return Response({ 'accepted media type': request.accepted_renderer.media_type })
- 要实现自定义内容协商方案,请覆盖BaseContentNegotiation。
Metadata
- REST框架包含一种可配置的机制,用于确定您的API如何响应OPTIONS请求。 这使您可以返回API模式或其他资源信息。
- 前,对于针对HTTP OPTIONS请求应返回哪种响应样式,尚无任何被广泛采用的约定,因此我们提供了一种临时样式,可返回一些有用的信息。
- 这是一个示例响应,演示了默认情况下返回的信息。
HTTP 200 OK Allow: GET, POST, HEAD, OPTIONS Content-Type: application/json { "name": "To Do List", "description": "List existing 'To Do' items, or create a new item.", "renders": [ "application/json", "text/html" ], "parses": [ "application/json", "application/x-www-form-urlencoded", "multipart/form-data" ], "actions": { "POST": { "note": { "type": "string", "required": false, "read_only": false, "label": "title", "max_length": 100 } } } }
- Setting the metadata scheme
REST_FRAMEWORK = { 'DEFAULT_METADATA_CLASS': 'rest_framework.metadata.SimpleMetadata' }
- 仅在一个视图起作用
class APIRoot(APIView): metadata_class = APIRootMetadata def get(self, request, format=None): return Response({ ... })
- REST框架软件包仅包含一个名为SimpleMetadata的元数据类实现。 如果要使用其他样式,则需要实现自定义元数据类。
- Creating scheme endpoints
- 如果您有创建通过常规GET请求访问的架构端点的特定要求,则可以考虑重新使用元数据API。
- 例如,可以在视图集上使用以下附加路由来提供可链接的架构端点。
@action(methods=['GET'], detail=False) def api_schema(self, request): meta = self.metadata_class() data = meta.determine_metadata(request, self) return Response(data)
- 您可能选择采用此方法的原因有两个,其中包括OPTIONS响应不可缓存。
Schema
- API架构是一个有用的工具,可用于各种用例,包括生成参考文档或驱动可与您的API交互的动态客户端库。
- Django REST Framework提供了对自动生成OpenAPI模式的支持。
- 此处省略
Format suffixes
- Web API的常见模式是在URL上使用文件名扩展名,以提供给定媒体类型的终结点。 例如,“ http://example.com/api/users.json”以提供JSON表示形式。
- 为API的URLconf中的每个单独的条目添加格式后缀模式是容易出错的,并且不是DRY,因此REST框架提供了将这些模式添加到URLConf的快捷方式。
- format_suffix_patterns(urlpatterns,suffix_required = False,allowed= None)
- 返回URL模式列表,该列表包括附加到所提供的每个URL模式的格式后缀模式。
- urlpatterns:必需。 URL模式列表。
- suffix_required:可选。 一个布尔值,指示URL中的后缀是可选的还是必需的。 默认为False,这意味着后缀默认为可选。
- allowed:可选。 有效格式后缀的列表或元组。 如果未提供,将使用通配符格式的后缀模式。
-
from rest_framework.urlpatterns import format_suffix_patterns from blog import views urlpatterns = [ url(r'^/$', views.apt_root), url(r'^comments/$', views.comment_list), url(r'^comments/(?P<pk>[0-9]+)/$', views.comment_detail) ] urlpatterns = format_suffix_patterns(urlpatterns, allowed=['json', 'html'])
- 当你使用 format_suffix_patterns ,你必须确保增加 format 关键字参数给视图函数或类视图
@api_view(['GET', 'POST']) def comment_list(request, format=None): # do stuff...
class CommentList(APIView): def get(self, request, format=None): # do stuff... def post(self, request, format=None): # do stuff...
- Using with i18n_patterns
-
url patterns = [ … ] urlpatterns = i18n_patterns( format_suffix_patterns(urlpatterns, allowed=['json', 'html']) )
- 如果使用Django提供的i18n_patterns函数以及format_suffix_patterns,则应确保将i18n_patterns函数用作最终函数或最外层函数。
-
Returning URLs
- Reverse 和
django.urls.reverse
, 有相同的行为reverse(viewname, *args, **kwargs)
from rest_framework.reverse import reverse from rest_framework.views import APIView from django.utils.timezone import now class APIRootView(APIView): def get(self, request): year = now().year data = { ... 'year-summary-url': reverse('year-summary', args=[year], request=request) } return Response(data)
- reverse_lazy
-
reverse_lazy(viewname, *args, **kwargs)
- 具有与django.urls.reverse_lazy相同的行为,除了它返回完全限定的URL(使用请求确定主机和端口)。
- 反向函数一样,您应将请求作为函数的关键字参数包括在内,例如:
api_root = reverse_lazy('api-root', request=request)
-
Exceptions
- REST框架的视图处理各种异常,并处理返回适当的错误响应。
- REST框架中引发的APIException子类。
- Django的Http404例外。
- Django的PermissionDenied异常。
- REST框架中引发的APIException子类。
- 在每种情况下,REST框架都会返回带有适当状态代码和内容类型的响应。 响应的正文将包含有关错误性质的任何其他详细信息。
- 增加错误码
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
REST_FRAMEWORK = { 'EXCEPTION_HANDLER': 'my_project.my_app.utils.custom_exception_handler' }
此处如果没有自定义,则默认为
'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler'
- APIException
- APIView class @api_view
- 提供自定义异常,请子类化APIException并在该类上设置.status_code,.default_detail和default_code属性。
- 如果您的API依赖于有时可能无法访问的第三方服务,则您可能希望实现“ 503 Service Unavailable” HTTP响应代码的异常。 您可以这样做:
-
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_detail() 返回文本描述和代码标识
>>> 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'}
- ParseError
ParseError(detail=None, code=None) 如果请求中包含格式错误的数据,则返回 400 Bad Request
- AuthenticationFailed
AuthenticationFailed(detail=None, code=None) 认证失败 401 Unauthenticated" 403 Forbidden"
- NoAuthenticated
NotAuthenticated(detail=None, code=None) 未认证 401 Unauthenticated "403 Forbidden
- PermissionDenied
PermissionDenied(detail=None, code=None) 无权限 403 Forbidden
- NotFound
NotFound(detail=None, code=None) 根据URL 找不到指定资源,404 Not Found"
- MethodNotAllowed
MethodNotAllowed(method, detail=None, code=None) "405 Method Not Allowed"
- NotAcceptable
NotAcceptable(detail=None, code=None) 无法满足的Accept标头 "415 Unsupported Media Type".
- Throttled
Throttled(wait=None, detail=None, code=None) 超过限流 429 Too Many Requests".
- ValidationError
ValidationError(detail, code=None)
- ValidationError异常与其他APIException类略有不同:
- detail参数是必需的,而不是可选的
- detail参数可以是错误详细信息的列表或字典,也可以是嵌套的数据结构。
- 按照惯例,您应该导入序列化器模块并使用完全限定的ValidationError样式,以便将其与Django的内置验证错误区分开。例如。引发serializers.ValidationError('此字段必须为整数值。'
- ValidationError类应用于验证序列器和字段,并由验证器类使用。当使用raise_exception关键字参数调用serializer.is_valid时,也会引发此错误:
- 默认情况下,此异常导致响应的HTTP状态代码为“ 400 Bad Request”。
- detail参数是必需的,而不是可选的
- ValidationError异常与其他APIException类略有不同:
- Generic Error Views
- Django REST Framework提供了两个错误视图,适合提供通用的JSON 500服务器错误和400错误请求响应。
- Django的默认错误视图提供HTML响应,这可能不适用于仅API的应用程序
- 返回
500
andapplication/json
handler500 = 'rest_framework.exceptions.server_error'
-
返回
400
andapplication/json
handler400 = 'rest_framework.exceptions.bad_request'
- Django REST Framework提供了两个错误视图,适合提供通用的JSON 500服务器错误和400错误请求响应。
Status Codes
- 不建议在响应中使用裸状态代码。 REST框架包括一组命名常量,您可以使用它们使代码更清晰易读。
-
from rest_framework import status from rest_framework.response import Response def empty_view(self): content = {'please move along': 'nothing to see here'} return Response(content, status=status.HTTP_404_NOT_FOUND)
- Information - 1XX 此类状态码表示临时响应。 默认情况下,REST框架中没有使用1xx状态代码。
HTTP_100_CONTINUE HTTP_101_SWITCHING_PROTOCOLS
- Succcessful 2XX 此类状态码表示已成功接收,理解并接受了客户的请求。
HTTP_200_OK HTTP_201_CREATED HTTP_202_ACCEPTED HTTP_203_NON_AUTHORITATIVE_INFORMATION HTTP_204_NO_CONTENT HTTP_205_RESET_CONTENT HTTP_206_PARTIAL_CONTENT HTTP_207_MULTI_STATUS HTTP_208_ALREADY_REPORTED HTTP_226_IM_USED
- Reirection -3XX 此类状态码表示用户代理需要采取进一步的措施才能满足请求。
HTTP_300_MULTIPLE_CHOICES HTTP_301_MOVED_PERMANENTLY HTTP_302_FOUND HTTP_303_SEE_OTHER HTTP_304_NOT_MODIFIED HTTP_305_USE_PROXY HTTP_306_RESERVED HTTP_307_TEMPORARY_REDIRECT HTTP_308_PERMANENT_REDIRECT
- Client Error -4XX
- 状态代码4xx类用于客户端似乎已出错的情况。 除响应HEAD请求外,服务器应包括一个实体,该实体包含错误情况的说明,以及它是暂时还是永久的情况。
-
HTTP_400_BAD_REQUEST HTTP_401_UNAUTHORIZED HTTP_402_PAYMENT_REQUIRED HTTP_403_FORBIDDEN HTTP_404_NOT_FOUND HTTP_405_METHOD_NOT_ALLOWED HTTP_406_NOT_ACCEPTABLE HTTP_407_PROXY_AUTHENTICATION_REQUIRED HTTP_408_REQUEST_TIMEOUT HTTP_409_CONFLICT HTTP_410_GONE HTTP_411_LENGTH_REQUIRED HTTP_412_PRECONDITION_FAILED HTTP_413_REQUEST_ENTITY_TOO_LARGE HTTP_414_REQUEST_URI_TOO_LONG HTTP_415_UNSUPPORTED_MEDIA_TYPE HTTP_416_REQUESTED_RANGE_NOT_SATISFIABLE HTTP_417_EXPECTATION_FAILED HTTP_422_UNPROCESSABLE_ENTITY HTTP_423_LOCKED HTTP_424_FAILED_DEPENDENCY HTTP_426_UPGRADE_REQUIRED HTTP_428_PRECONDITION_REQUIRED HTTP_429_TOO_MANY_REQUESTS HTTP_431_REQUEST_HEADER_FIELDS_TOO_LARGE HTTP_451_UNAVAILABLE_FOR_LEGAL_REASONS
- Server Error -5XX
- 以数字“ 5”开头的响应状态代码表示服务器知道服务器已出错或无法执行请求的情况。 除响应HEAD请求外,服务器应包括一个实体,该实体包含错误情况的说明,以及它是暂时还是永久的情况。
-
HTTP_500_INTERNAL_SERVER_ERROR HTTP_501_NOT_IMPLEMENTED HTTP_502_BAD_GATEWAY HTTP_503_SERVICE_UNAVAILABLE HTTP_504_GATEWAY_TIMEOUT HTTP_505_HTTP_VERSION_NOT_SUPPORTED HTTP_506_VARIANT_ALSO_NEGOTIATES HTTP_507_INSUFFICIENT_STORAGE HTTP_508_LOOP_DETECTED HTTP_509_BANDWIDTH_LIMIT_EXCEEDED HTTP_510_NOT_EXTENDED HTTP_511_NETWORK_AUTHENTICATION_REQUIRED
- 帮助函数
is_informational() # 1xx is_success() # 2xx is_redirect() # 3xx is_client_error() # 4xx is_server_error() # 5xx
Testing
- APIRequestFactory 继承自Django 的RequestFactory
- Creating test requests
- 提供 get() post() put() patch() delete() options()
from rest_framework.test import APIRequestFactory # Using the standard RequestFactory API to create a form POST request factory = APIRequestFactory() request = factory.post('/notes/', {'title': 'new idea'})
- 使用format 参数确定参数类型,提交数据
# Create a JSON POST request factory = APIRequestFactory() request = factory.post('/notes/', {'title': 'new idea'}, format='json')
- 默认情况下,可用格式为“ multipart”和“ json”。 为了与Django现有的RequestFactory兼容,默认格式为“ multipart”。
- 明确编码的请求主题
- 如果需要显式编码请求正文,则可以通过设置content_type标志来实现。
request = factory.post('/notes/', json.dumps({'title': 'new idea'}), content_type='application/json')
- 如果需要显式编码请求正文,则可以通过设置content_type标志来实现。
- 使用表格数据进行PUT 和PATCH
- 值得注意的是Django的RequestFactory和REST框架的APIRequestFactory之间的差异是,将为.post()以外的方法编码多部分表单数据。
factory = APIRequestFactory() request = factory.put('/notes/547/', {'title': 'remember to email dave'})
- 值得注意的是Django的RequestFactory和REST框架的APIRequestFactory之间的差异是,将为.post()以外的方法编码多部分表单数据。
- 使用Django的RequestFactory,您需要自己对数据进行显式编码:
-
from django.test.client import encode_multipart, RequestFactory factory = RequestFactory() data = {'title': 'remember to email dave'} content = encode_multipart('BoUnDaRyStRiNg', data) content_type = 'multipart/form-data; boundary=BoUnDaRyStRiNg' request = factory.put('/notes/547/', content, content_type=content_type)
-
- 提供 get() post() put() patch() delete() options()
- Forcing authentication
- 使用请求工厂直接测试视图时,通常很方便的是能够直接对请求进行身份验证,而不必构造正确的身份验证凭据。
- 要强制验证请求,请使用force_authenticate()方法。
from rest_framework.test import force_authenticate factory = APIRequestFactory() user = User.objects.get(username='olivia') view = AccountDetail.as_view() # Make an authenticated request to the view... request = factory.get('/accounts/django-superstars/') force_authenticate(request, user=user) response = view(request)
force_authenticate(request, user=None, token=None)
.user = User.objects.get(username='olivia') request = factory.get('/accounts/django-superstars/') force_authenticate(request, user=user, token=user.auth_token)
force_authenticate直接将request.user设置为内存中的用户实例。 如果要在多个测试中重用同一用户实例以更新保存的用户状态,则可能需要在测试之间调用refresh_from_db()。
- 这意味着直接在请求对象上设置属性可能并不总是具有预期的效果。 例如,直接设置.token将无效,而直接设置.user仅在使用会话身份验证时才有效。
-
# Request will only authenticate if `SessionAuthentication` is in use. request = factory.get('/accounts/django-superstars/') request.user = user response = view(request)
-
- Forcing CSRF validation
- 默认情况下,使用APIRequestFactory创建的请求在传递到REST框架视图时将不会应用CSRF验证。 如果需要显式打开CSRF验证,则可以通过在实例化工厂时设置force_csrf_checks标志来实现。
-
factory = APIRequestFactory(enforce_csrf_checks=True)
- 因为在使用常规Django时,CSRF验证在中间件中进行,而中间件在直接测试视图时不会运行
- 使用REST框架时,CSRF验证在视图内部进行,因此请求工厂需要禁用视图级CSRF检查。
- APIClient
- 继承自Django Client 类
- Making requests
- 支持
.get()
,.post()
,.put()
,.patch()
,.delete()
,.head()
and.options()
from rest_framework.test import APIClient client = APIClient() client.post('/notes/', {'title': 'new idea'}, format='json')
- 支持
- Authenticating
- login(**kwargs)
- login方法的功能与Django常规Client类的功能完全相同。 这使您可以针对任何包含SessionAuthentication的视图对请求进行身份验证。
# Make all requests in the context of a logged in session. client = APIClient() client.login(username='lauren', password='secret')
- 登出
# Log out client.logout()
- login方法的功能与Django常规Client类的功能完全相同。 这使您可以针对任何包含SessionAuthentication的视图对请求进行身份验证。
- credentials(**kwargs)
- 用于添加请求头,作用于其他请求子类
-
from rest_framework.authtoken.models import Token from rest_framework.test import APIClient # Include an appropriate `Authorization:` header on all requests. token = Token.objects.get(user__username='lauren') client = APIClient() client.credentials(HTTP_AUTHORIZATION='Token ' + token.key)
- 请注意,第二次调用凭据将覆盖所有现有凭据。 您可以通过不带任何参数的方法来取消设置任何现有的凭据。
-
# Stop including any credentials client.credentials()
- 凭据方法适用于测试需要身份验证标头的API,例如基本身份验证,OAuth1a和OAuth2身份验证以及简单令牌身份验证方案。
- force_authenticate(user=None,token=None)
- 有时,您可能希望完全绕过身份验证,并强制将测试客户端的所有请求自动视为已身份验证。
- 如果您正在测试API,但又不想构造有效的身份验证凭据来发出测试请求,则这可能是一个有用的快捷方式。
-
user = User.objects.get(username='lauren') client = APIClient() client.force_authenticate(user=user)
- 要取消对后续请求的身份验证,请调用force_authenticate将用户和/或令牌设置为“无”。
-
client.force_authenticate(user=None)
- CSRF validation
- CSRF 测试视图的时候默认不开启,如果要开启
-
client = APIClient(enforce_csrf_checks=True)
- 与往常一样,CSRF验证仅适用于任何经过会话身份验证的视图。 这意味着仅当通过调用login()登录客户端后,CSRF验证才会发生。
- login(**kwargs)
- RequestsClient
- 您期望主要通过另一个Python服务与API进行接口,并希望在与客户端将看到的相同级别上测试服务。
- 这将显示与您直接使用请求会话完全相同的界面
from rest_framework.test import RequestsClient client = RequestsClient() response = client.get('http://testserver/users/') assert response.status_code == 200
- 与数据库交互
- 如果您要编写仅与服务接口交互的测试,则RequestsClient类很有用。 这比使用标准Django测试客户端要严格一些,因为这意味着所有交互都应通过API进行。
- 如果使用的是RequestsClient,则需要确保测试设置和结果断言是作为常规API调用执行的,而不是直接与数据库模型进行交互。 例如,您无需列出Customer.objects.count()== 3,而是列出客户端点,并确保它包含三个记录。
- 如果您要编写仅与服务接口交互的测试,则RequestsClient类很有用。 这比使用标准Django测试客户端要严格一些,因为这意味着所有交互都应通过API进行。
- 请求头和认证
- 可以使用与使用标准request.Session实例相同的方式来提供自定义标头和身份验证凭据。
-
from requests.auth import HTTPBasicAuth client.auth = HTTPBasicAuth('user', 'pass') client.headers.update({'x-test': 'true'}
- CSRF
- 如果您使用的是SessionAuthentication,则需要为所有POST,PUT,PATCH或DELETE请求包括一个CSRF令牌。
- 您可以按照基于JavaScript的客户端将使用的相同流程进行操作。 首先发出GET请求以获得CRSF令牌,然后在随后的请求中显示该令牌。
client = RequestsClient() # Obtain a CSRF token. response = client.get('http://testserver/homepage/') assert response.status_code == 200 csrftoken = response.cookies['csrftoken'] # Interact with the API. response = client.post('http://testserver/organisations/', json={ 'name': 'MegaCorp', 'status': 'active' }, headers={'X-CSRFToken': csrftoken}) assert response.status_code == 200
- Live Tests
- 通过仔细使用,RequestsClient和CoreAPIClient都可以编写可以在开发中运行或直接在登台服务器或生产环境中运行的测试用例。
- 使用这种样式创建一些核心功能的基本测试是验证实时服务的有效方法。 这样做可能需要仔细注意设置和拆卸,以确保测试以不会直接影响客户数据的方式运行。
- CoreAPIClient
- CoreAPIClient允许您使用Python coreapi客户端库与您的API进行交互。
-
# Fetch the API schema client = CoreAPIClient() schema = client.get('http://testserver/schema/') # Create a new organisation params = {'name': 'MegaCorp', 'status': 'active'} client.action(schema, ['organisations', 'create'], params) # Ensure that the organisation exists in the listing data = client.action(schema, ['organisations', 'list']) assert(len(data) == 1) assert(data == [{'name': 'MegaCorp', 'status': 'active'}])
- CoreAPIClient允许您使用Python coreapi客户端库与您的API进行交互。
- Headers&Authentication
from requests.auth import HTTPBasicAuth client = CoreAPIClient() client.session.auth = HTTPBasicAuth('user', 'pass') client.session.headers.update({'x-test': 'true'})
- API Test cases
-
APISimpleTestCase
APITransactionTestCase
APITestCase
APILiveServerTestCase
-
from django.urls import reverse from rest_framework import status from rest_framework.test import APITestCase from myproject.apps.core.models import Account class AccountTests(APITestCase): def test_create_account(self): """ Ensure we can create a new account object. """ url = reverse('account-list') data = {'name': 'DabApps'} response = self.client.post(url, data, format='json') self.assertEqual(response.status_code, status.HTTP_201_CREATED) self.assertEqual(Account.objects.count(), 1) self.assertEqual(Account.objects.get().name, 'DabApps')
-
- URLPatterns TestCase
-
from django.urls import include, path, reverse from rest_framework.test import APITestCase, URLPatternsTestCase class AccountTests(APITestCase, URLPatternsTestCase): urlpatterns = [ path('api/', include('api.urls')), ] def test_create_account(self): """ Ensure we can create a new account object. """ url = reverse('account-list') response = self.client.get(url, format='json') self.assertEqual(response.status_code, status.HTTP_200_OK) self.assertEqual(len(response.data), 1)
-
- Testing Responses
- checking the response data
- 在检查测试响应的有效性时,通常更方便的方法是检查创建响应的数据,而不是检查完全呈现的响应。
- 检查response.data更容易:
response = self.client.get('/users/4/') self.assertEqual(response.data, {'id': 4, 'username': 'lauren'})
而不是检查response.content的解析结果:
response = self.client.get('/users/4/') self.assertEqual(json.loads(response.content), {'id': 4, 'username': 'lauren'})
- 在检查测试响应的有效性时,通常更方便的方法是检查创建响应的数据,而不是检查完全呈现的响应。
- Redndering responses
- 如果您直接使用APIRequestFactory测试视图,则返回的响应将尚未呈现,因为模板响应的呈现是由Django的内部请求-响应周期执行的。
- 为了访问response.content,您首先需要呈现响应。
view = UserDetail.as_view() request = factory.get('/users/4') response = view(request, pk='4') response.render() # Cannot access `response.content` without this. self.assertEqual(response.content, '{"username": "lauren", "id": 4}')
- checking the response data
- Configuration
- Setting the default format
- 可以使用TEST_REQUEST_DEFAULT_FORMAT设置键来设置用于发出测试请求的默认格式
- 例如,要始终默认将JSON用于测试请求,而不是标准的多部分表单请求,请在settings.py文件中设置以下内容:
REST_FRAMEWORK = { ... 'TEST_REQUEST_DEFAULT_FORMAT': 'json' }
- Stting the available formats
- 如果您需要使用multipart或json请求之外的其他测试请求,则可以通过设置TEST_REQUEST_RENDERER_CLASSES设置来进行。
- 例如,要增加对在测试请求中使用format ='html'的支持,您的settings.py文件中可能会有类似的内容。
-
REST_FRAMEWORK = { ... 'TEST_REQUEST_RENDERER_CLASSES': [ 'rest_framework.renderers.MultiPartRenderer', 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.TemplateHTMLRenderer' ] }
Settings
- REST框架的配置全部在单个Django设置(称为REST_FRAMEWORK)中命名空间。
REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': [ 'rest_framework.renderers.JSONRenderer', ], 'DEFAULT_PARSER_CLASSES': [ 'rest_framework.parsers.JSONParser', ] }
- Accessing settings
- 如果需要在项目中访问REST框架的API设置的值,则应使用api_settings对象。 例如。
from rest_framework.settings import api_settings print(api_settings.DEFAULT_AUTHENTICATION_CLASSES)
- api_settings对象将检查是否有任何用户定义的设置,否则将退回到默认值。 使用字符串导入路径引用类的任何设置都将自动导入并返回引用的类,而不是字符串文字。
- 如果需要在项目中访问REST框架的API设置的值,则应使用api_settings对象。 例如。
- API Reference
- API policy settings
- 以下设置控制基本的API策略,并应用于每个基于APIView类的视图或基于@api_view函数的视图。
- 渲染器类的列表或元组,确定返回响应对象时可以使用的默认渲染器集。
[ 'rest_framework.renderers.JSONRenderer', 'rest_framework.renderers.BrowsableAPIRenderer', ]
- DEFAULT_PARSER_CLASSES
- 解析器类的列表或元组,确定访问request.data属性时使用的默认解析器集。
-
[ 'rest_framework.parsers.JSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser' ]
- DEFAULT_AUTHENTICATION_CLASSES
- 身份验证类的列表或元组,用于确定访问request.user或request.auth属性时使用的默认身份验证器集。
-
[ 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication' ]
- DEFAULT_PERMISSION_CLASSES
- 权限类列表或元组,用于确定在视图开始时检查的默认权限集。 列表中的每个类都必须授予权限。
[ 'rest_framework.permissions.AllowAny', ]
- 权限类列表或元组,用于确定在视图开始时检查的默认权限集。 列表中的每个类都必须授予权限。
- DEFAULT_THROTTLE_CLASSES Default []
- DEFAULT_CONTENT_NEGOTIATION_CLASS Default:
'rest_framework.negotiation.DefaultContentNegotiation'
- DEFAULTE_SCHEMA_CLASS 视图检查器类,将用于模式生成。
- Default:
'rest_framework.schemas.openapi.AutoSchema'
- Default:
- Generic view settings
- DEFAULT_FILTER_BACKENDS
- DEFAULT_PAGINATION_CLASS
- PAGE_SIZE
- SEARCH_PARAM
- ORDERING_PARAM
- Versioning settings
- DEFAULT_VERSIONS
- ALLOWED_VERSIONS
- VERSION_PARAM
- Authentication settings
- UNAUTHENTICATED_USER
- 用于初始化未经身份验证的请求的request.user的类。 (如果要完全删除身份验证,例如通过从INSTALLED_APPS中删除django.contrib.auth,请将UNAUTHENTICATED_USER设置为None。)
- 默认值:django.contrib.auth.models.AnonymousUser
- UNAUTHENTICATED_TOKEN
- 用于未经身份验证的请求初始化request.auth的类。
- Default:
None
- UNAUTHENTICATED_USER
- Test settings
- TEST_REQUEST_DEFAULT_FORMAT
- 发出测试请求时应使用的默认格式。
- 这应该与TEST_REQUEST_RENDERER_CLASSES设置中的渲染器类之一的格式匹配。
- 默认值:“ multipart”
- 发出测试请求时应使用的默认格式。
- TEST_REQUEST_RENDERER_CLASSES
- 构建测试请求时支持的渲染器类。
- 构造测试请求时,可以使用任何这些渲染器类的格式,例如:client.post('/ users',{'username':'jamie'},format ='json')
- 默认
[ 'rest_framework.renderers.MultiPartRenderer', 'rest_framework.renderers.JSONRenderer' ]
- 构建测试请求时支持的渲染器类。
- TEST_REQUEST_DEFAULT_FORMAT
- Schema generation controls
- SCHEMA_COERCE_PATH_PK
- 如果设置,则在生成架构路径参数时,会将URL conf中的“ pk”标识符映射到实际的字段名称。
- 通常,这将是“ id”。 由于“主键”是实现细节,因此给出了更合适的表示形式,而“标识符”是更笼统的概念。
- Default:
True
- SCHEMA_COERCH_METHOD_NAMES
- 如果设置,则用于将内部视图集方法名称映射到架构生成中使用的外部操作名称。 这使我们能够生成比在代码库内部使用的名称更适合外部表示的名称。
- Default:
{'retrieve': 'read', 'destroy': 'delete'}
- SCHEMA_COERCE_PATH_PK
- Content type controls
- URL_FORMAT_OVERRIDE
- URL参数的名称,可以通过在请求URL中使用format =…query参数来覆盖默认的内容协商Accept标头行为。
- 如果此设置的值为None,则URL格式替代将被禁用。
-
Default: 'format'
- FORMAT_SUFFIX_KWARGS
- URL conf中的参数名称,可用于提供格式后缀。 当使用format_suffix_patterns包括后缀URL模式时,将应用此设置。
- Default:
'format'
- URL conf中的参数名称,可用于提供格式后缀。 当使用format_suffix_patterns包括后缀URL模式时,将应用此设置。
- URL_FORMAT_OVERRIDE
- Date and time formatting
- DATATIME_FORMATE
- DETETIME_INPUT_FORMATS
- DATA_FORMAT
- DATA_NPUT_FORMATS
- TIME_FORMAT
- TIME_INPUT_FORMATS
- Encodings
- UNICODE_JSON ,设置为True 时可包含特殊符号,不会转义非ascii字符 Default:
True
{"unicode black star":"★"}
- UNICODE_JSON ,设置为False时,JSON响应将转义非ascii字符
{"unicode black star":"u2605"}
- COMPACT_JSON Default:
True
- 设置为True时,JSON响应将返回紧凑的表示形式,在':'和','字符后没有空格。 例如:
{"is_admin":false,"email":"jane@example"}
- 设置为False时,JSON响应将返回更多详细的表示形式,如下所示:
{"is_admin": false, "email": "jane@example"}
- 设置为True时,JSON响应将返回紧凑的表示形式,在':'和','字符后没有空格。 例如:
- STRICT_JSON
- 设置为True时,JSON呈现和解析将仅遵循语法上有效的JSON,从而为Python的json模块接受的扩展float值(nan,inf,-inf)引发异常
- 建议使用此设置,因为通常不支持这些值。 例如,Javascript的JSON.Parse和PostgreSQL的JSON数据类型都不接受这些值。
- 设置为False时,将允许JSON呈现和解析。 但是,这些值仍然无效,需要在您的代码中进行特殊处理。
- 默认值:True
- COERCE_DECIMA_TO_STRING
- 在不支持本机十进制类型的API表示中返回十进制对象时,通常最好将值作为字符串返回。 这避免了二进制浮点实现时精度的损失。
- 设置为True时,序列化程序DecimalField类将返回字符串而不是Decimal对象。
- 设置为False时,序列化程序将返回Decimal对象,默认的JSON编码器将以浮点数返回。
- 默认值:True
- 在不支持本机十进制类型的API表示中返回十进制对象时,通常最好将值作为字符串返回。 这避免了二进制浮点实现时精度的损失。
- UNICODE_JSON ,设置为True 时可包含特殊符号,不会转义非ascii字符 Default:
- View names and descriptions
- 以下设置用于生成视图名称和描述,这些视图名称和描述用于响应OPTIONS请求以及可浏览API。
- VIEW_NAME_FUNCTION
- 一个字符串,表示生成视图名称时应使用的函数。
-
view_name(self)
-
self视图实例。 通常,在生成描述性名称时,名称函数将通过访问self .__ class __.__ name__来检查类的名称。
-
如果视图实例继承了ViewSet,则可能已使用几个可选参数对其进行了初始化:
- name:在视图集中明确提供给视图的名称。 通常,提供时应按原样使用此值。
- suffix:在视图集中区分单个视图时使用的文本。 此参数与名称互斥。
- detail:布尔值,用于将视图集中的单个视图区分为“列表”视图还是“详细”视图。
- Default: 'rest_framework.views.get_view_name'
-
- VIEW_DESCRIPTION_FUNCTION
- 一个字符串,表示生成视图描述时应使用的功能。
- 可以更改此设置以支持默认的markdown以外的标记样式。 例如,您可以使用它来支持在可浏览API中输出的视图文档字符串中的rst标记。
view_description(self, html=False)
- Default:
'rest_framework.views.get_view_description'
- 一个字符串,表示生成视图描述时应使用的功能。
- HTML Seletc Field cutoffs
- 用于在可浏览的API中呈现关系字段的选择字段截止的全局设置。
- HTML_SELECT_cutoff efault: 1000
- HTML_SELECT_CUTOFF_TEXT
- Default:
"More than {count} items..."
- Default:
- Miscellaneous settings
- EXCEPTION_HANDLER
- 一个字符串,表示在返回任何给定异常的响应时应使用的函数。 如果函数返回无,将引发500错误。
- 可以更改此设置以支持错误响应,而不是默认的{“ detail”:“ Failure ...”}响应。 例如,您可以使用它来提供API响应,例如{“ errors”:[{“ message”:“ Failure ...”,“ code”:“”} ...]}。
-
exception_handler(exc, context)
exc
: The exception.-
Default:
'rest_framework.views.exception_handler'
- NON_FIELD_ERRORS_KEY
- 一个字符串,它表示应该用于序列化程序错误的键,该错误不引用特定字段,而是常规错误。
- Default:
'non_field_errors'
- URL_FIELD_NAME
- 一个字符串,代表应用于HyperlinkedModelSerializer生成的URL字段的密钥。
- Default:
'url'
NUM_PROXIES - 0或更大的整数,可用于指定API在其后运行的应用程序代理的数量。
- 这允许节流以更准确地标识客户端IP地址。 如果设置为None,那么节流类将使用不太严格的IP匹配。
- Default:
None
- EXCEPTION_HANDLER