DRF框架基本组件之频率&解析器&分页
频率控制
限制类似于权限,因为它确定是否应该授权请求。Throttles表示临时状态,用于控制客户端可以对API发出的请求的速率。
与权限一样,可以使用多个限制。您的API可能对未经身份验证的请求具有限制性限制,并且对经过身份验证的请求限制较少。
您可能希望使用多个限制的另一种情况是,如果您需要对API的不同部分施加不同的约束,因为某些服务特别是资源密集型。
如果要同时施加突发限制速率和持续限制速率,也可以使用多个限制。例如,您可能希望将用户限制为每分钟最多60个请求,每天1000个请求。
Throttles不一定仅涉及限速请求。例如,存储服务可能还需要对带宽进行限制,并且付费数据服务可能希望对正在访问的特定数量的记录进行限制。
如何确定节流量
与权限和身份验证一样,REST框架中的限制始终定义为类列表。
在运行视图的主体之前,检查列表中的每个节流阀。如果任何油门检查失败,exceptions.Throttled
将引发异常,并且视图的主体将不会运行。
设置限制策略
可以使用DEFAULT_THROTTLE_CLASSES
和DEFAULT_THROTTLE_RATES
设置全局设置默认限制策略。例如。
REST_FRAMEWORK = { 'DEFAULT_THROTTLE_CLASSES': ( 'rest_framework.throttling.AnonRateThrottle', 'rest_framework.throttling.UserRateThrottle' ), 'DEFAULT_THROTTLE_RATES': { 'anon': '100/day', 'user': '1000/day' } }
用在速率的描述DEFAULT_THROTTLE_RATES
可以包括second
,minute
,hour
或day
作为节流段。
您还可以使用APIView
基于类的视图在每个视图或每个视图集的基础上设置限制策略。
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)
设置自定义的频率控制器
在app01.service.throttles.py中:
from rest_framework.throttling import BaseThrottle VISIT_RECORD={} class VisitThrottle(BaseThrottle): def __init__(self): self.history=None def allow_request(self,request,view): remote_addr = request.META.get('REMOTE_ADDR') print(remote_addr) import time ctime=time.time() if remote_addr not in VISIT_RECORD: VISIT_RECORD[remote_addr]=[ctime,] return True history=VISIT_RECORD.get(remote_addr) self.history=history while history and history[-1]<ctime-60: history.pop() if len(history)<3: history.insert(0,ctime) return True else: return False def wait(self): import time ctime=time.time() return 60-(ctime-self.history[-1])
在views.py中:
from app01.service.throttles import * class BookViewSet(generics.ListCreateAPIView): throttle_classes = [VisitThrottle,] queryset = Book.objects.all() serializer_class = BookSerializers
全局视图throttle
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",] }
内置throttle类
在app01.service.throttles.py修改为:
class VisitThrottle(SimpleRateThrottle): scope="visit_rate" def get_cache_key(self, request, view): return self.get_ident(request)
settings.py设置:
REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.service.auth.Authentication",], "DEFAULT_PERMISSION_CLASSES":["app01.service.permissions.SVIPPermission",], "DEFAULT_THROTTLE_CLASSES":["app01.service.throttles.VisitThrottle",], "DEFAULT_THROTTLE_RATES":{ "visit_rate":"5/m", } }
REST 框架包括一些内置的Parser类,允许你接受各种媒体类型的请求。还支持定义自己的自定义解析器,这使你可以灵活地设计API接受的媒体类型。
解析器如何确定
一组视图的有效解析器总是被定义为一个类的列表。当访问request.data
时,REST框架将检查传入请求中的Content-Type
头,并确定用于解析请求内容的解析器。
注意: 开发客户端应用程序时应该始终记住在HTTP请求中发送数据时确保设置Content-Type
头。
如果你不设置内容类型,大多数客户端将默认使用'application/x-www-form-urlencoded'
,而这可能并不是你想要的。
举个例子,如果你使用jQuery的.ajax() 方法发送json
编码数据,你应该确保包含contentType:'application / json'
设置。
设置解析器
可以使用DEFAULT_PARSER_CLASSES
设置全局默认的解析器集。例如,以下设置将仅允许具有JSON
内容的请求,而不是JSON或表单数据的默认值。
REST_FRAMEWORK = { 'DEFAULT_PARSER_CLASSES': ( 'rest_framework.parsers.JSONParser', ) }
你还可以设置用于单个视图或视图集的解析器, 使用APIView
类视图。
from rest_framework.parsers import JSONParser from rest_framework.response import Response from rest_framework.views import APIView class ExampleView(APIView): """ 可以接收JSON内容POST请求的视图。 """ parser_classes = (JSONParser,) def post(self, request, format=None): return Response({'received data': request.data})
或者,如果你使用基于方法的视图的@api_view
装饰器。
from rest_framework.decorators import api_view from rest_framework.decorators import parser_classes @api_view(['POST']) @parser_classes((JSONParser,)) def example_view(request, format=None): """ 可以接收JSON内容POST请求的视图 """ return Response({'received data': request.data})
分页
REST框架包括对可自定义分页样式的支持。这允许您修改将大型结果集拆分为单个数据页的方式。
分页API可以支持:
- 分页链接是作为响应内容的一部分提供的。
- 响应标头中包含的分页链接,例如
Content-Range
或Link
。
内置样式目前都使用包含在响应内容中的链接。使用可浏览API时,此样式更易于访问。
只有在使用通用视图或视图集时,才会自动执行分页。如果您使用常规APIView
,则需要自己调用分页API以确保返回分页响应。有关示例,请参阅mixins.ListModelMixin
和generics.GenericAPIView
类的源代码。
可以通过将分页类设置为关闭分页None
。
设置分页样式
可以使用DEFAULT_PAGINATION_CLASS
和PAGE_SIZE
设置键全局设置默认分页样式。例如,要使用内置限制/偏移分页,您可以执行以下操作:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination', 'PAGE_SIZE': 100 }
请注意,您需要设置分页类和应该使用的页面大小。
您还可以使用该pagination_class
属性在单个视图上设置分页类。通常,您希望在整个API中使用相同的分页样式,尽管您可能希望基于每个视图改变分页的各个方面,例如默认或最大页面大小。
修改分页样式
如果要修改分页样式的特定方面,则需要覆盖其中一个分页类,并设置要更改的属性。
class LargeResultsSetPagination(PageNumberPagination): page_size = 1000 page_size_query_param = 'page_size' max_page_size = 10000 class StandardResultsSetPagination(PageNumberPagination): page_size = 100 page_size_query_param = 'page_size' max_page_size = 1000
然后,您可以使用以下.pagination_class
属性将新样式应用于视图:
class BillingRecordsView(generics.ListAPIView): queryset = Billing.objects.all() serializer_class = BillingRecordsSerializer pagination_class = LargeResultsSetPagination
或者使用DEFAULT_PAGINATION_CLASS
设置键全局应用样式。例如:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination' }
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": [
…
]
}
使用:
要PageNumberPagination
全局启用该样式,请使用以下配置,PAGE_SIZE
根据需要进行修改:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 100 }
在GenericAPIView
子类上,您还可以将pagination_class
属性设置为PageNumberPagination
基于每个视图进行选择。
所述PageNumberPagination
类包括多个可重写修改分页样式属性。
要设置这些属性,您应该覆盖PageNumberPagination
该类,然后启用上面的自定义分页类。
django_paginator_class
- 要使用的Django Paginator类。默认值是django.core.paginator.Paginator
,对于大多数用例来说应该没问题。page_size
- 表示页面大小的数值。如果设置,则会覆盖该PAGE_SIZE
设置。默认值与PAGE_SIZE
设置键的值相同。page_query_param
- 一个字符串值,指示用于分页控件的查询参数的名称。page_size_query_param
- 如果设置,这是一个字符串值,指示允许客户端基于每个请求设置页面大小的查询参数的名称。默认为None
,表示客户端可能无法控制请求的页面大小。max_page_size
- 如果设置,这是一个数值,表示允许的最大请求页面大小。此属性仅在page_size_query_param
设置时有效。last_page_strings
- 字符串值的列表或元组,指示可用于page_query_param
请求集合中最后一页的值。默认为('last',)
template
- 在可浏览API中呈现分页控件时要使用的模板的名称。可以重写以修改呈现样式,或设置为None
完全禁用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": [
…
]
}
使用
要LimitOffsetPagination
全局启用该样式,请使用以下配置:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination' }
您也可以选择设置PAGE_SIZE
密钥。如果PAGE_SIZE
还使用该参数,则limit
查询参数将是可选的,并且客户端可以省略该参数。
在GenericAPIView
子类上,您还可以将pagination_class
属性设置为LimitOffsetPagination
基于每个视图进行选择。
组态
所述LimitOffsetPagination
类包括多个可重写修改分页样式属性。
要设置这些属性,您应该覆盖LimitOffsetPagination
该类,然后启用上面的自定义分页类。
default_limit
- 一个数值,指示客户端在查询参数中未提供限制时使用的限制。默认值与PAGE_SIZE
设置键的值相同。limit_query_param
- 表示“limit”查询参数名称的字符串值。默认为'limit'
。offset_query_param
- 表示“偏移”查询参数名称的字符串值。默认为'offset'
。max_limit
- 如果设置,则这是一个数值,表示客户端可能请求的最大允许限制。默认为None
。template
- 在可浏览API中呈现分页控件时要使用的模板的名称。可以重写以修改呈现样式,或设置为None
完全禁用HTML分页控件。默认为"rest_framework/pagination/numbers.html"
。