频率组件类似于权限组件, 它判断是否给予请求通过. 频率指示临时状态, 并用于控制客户端可以向 API 发出的请求的速率.
与权限一样, 可以使用多个调节器. API 可能会对未经身份验证的请求进行限制, 而对于经过身份验证的请求则进行限制较少.
例如, 可以将用户限制为每分钟最多 60 个请求, 每天最多 1000 个请求.
自定义频率组件
使用方式与权限, 认证组件几乎相同
该方式没有 DRF 提供的方式简洁
- import time
- import math
- from rest_framework import exceptions
- class MyException(exceptions.Throttled):
- default_detail = '连接次数过多'
- extra_detail_plural = extra_detail_singular = '请在 {wait} 秒内访问'
- def __init__(self, wait=None, detail=None, code=None):
- super().__init__(wait=wait, detail=detail, code=code)
- class VisitThrottle():
- user_visit_information = dict()
- visited_times = 1
- period = 60
- allow_times_per_minute = 5
- first_time_visit = True
- def allow_request(self, request, view):
- self.request_host = request_host = request.META.get("REMOTE_ADDR")
- current_user_info = self.user_visit_information.get(request_host, None)
- if not self.__class__.first_time_visit:
- self.user_visit_information[request_host][0] += 1
- current_visit_times = self.user_visit_information[request_host][0]
- if current_visit_times> self.allow_times_per_minute:
- if self._current_time - current_user_info[1] <= self.period:
- if len(current_user_info)> 2:
- current_user_info[2] = self._time_left
- else:
- current_user_info.append(self._time_left)
- view.throttled = self.throttled
- return None
- else:
- self.__class__.first_time_visit = True
- if self.first_time_visit:
- self.__class__.first_time_visit = False
- self._initial_infomation()
- return True
- def wait(self):
- return self.period - self.user_visit_information[self.request_host][2]
- def throttled(self, request, wait):
- raise MyException(wait=wait)
- @property
- def _current_time(self):
- return time.time()
- @property
- def _time_left(self):
- return math.floor(self._current_time - self.user_visit_information.get(self.request_host)[1])
- def _initial_infomation(self):
- self.user_visit_information[self.request_host] = [self.visited_times, self._current_time]
基于每个视图设置频率:
- class BookView(ModelViewSet):# 指定频率类, 固定写法
- throttle_classes = [RateThrottle]
- # 获取数据源, 固定写法
- queryset = models.Book.objects.all()
- # 序列化类, 固定写法
- serializer_class = BookSerializer
使用 DRF 简单频率控制(局部)
- from rest_framework.throttling import SimpleRateThrottle
- class RateThrottle(SimpleRateThrottle):
- # 每分钟最多五次
- rate = '5/m'
- def get_cache_key(self, request, view):
- return self.get_ident(request)
rate 代表访问评率, 上面表示每分钟五次, get_cache_key 是必须存在的, 它的返回值告诉当前频率控制组件要使用什么方式区分访问者(比如 ip 地址).
在视图中使用:
- class BookView(ModelViewSet):
- # 指定频率类, 固定写法
- throttle_classes = [RateThrottle]
- # 获取数据源, 固定写法
- queryset = models.Book.objects.all()
- # 序列化类, 固定写法
- serializer_class = BookSerializer
全局频率控制
首先定义一个频率控制类, 并且必须继承 SimpleRateThrottle 这个类, 它是 DRF 提供的一个方便的频率控制类, 请看下面的代码:
- from rest_framework.throttling import SimpleRateThrottle
- class RateThrottle(SimpleRateThrottle):
- scope = "visit_rate"
- def get_cache_key(self, request, view):
- return self.get_ident(request)
在全局配置频率控制参数:
- REST_FRAMEWORK = {
- "DEFAULT_THROTTLE_CLASSES": ('app.utils.throttles.RateThrottle',),
- "DEFAULT_THROTTLE_RATES": {
- "visit_rate": "5/m"
- }
- }
这样就实现了, 每分钟最多五次访问的逻辑.
另外, 可以使用 DEFAULT_THROTTLE_CLASSES 和 DEFAULT_THROTTLE_RATES 设置全局设置默认的限制策略.
例如:
- REST_FRAMEWORK = {
- 'DEFAULT_THROTTLE_CLASSES': [
- 'rest_framework.throttling.AnonRateThrottle',
- 'rest_framework.throttling.UserRateThrottle'
- ],
- 'DEFAULT_THROTTLE_RATES': {
- # 游客每天访问次数不能超过 100 次
- 'anon': '100/day',
- # 用户每天访问次数不能超过 1000 次
- 'user': '1000/day'
- }
- }
响应器
在使用 DRF 的 Response 类来将数据响应给客户端时, 不管是 POSTMAN 工具还是浏览器, 都能浏览到经过格式化后的, 清晰易懂数据, DRF 是怎么做的呢? 其实就是通过响应器组件
响应器组件的使用
如果不需要使用 DRF 提供给浏览器的格式化后的数据, 只需要禁止该响应方式即可:
- from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
- class BookView(ModelViewSet):
- # 指定响应器类, 固定写法, 返回 JSON 格式数据
- renderer_classes = [JSONRenderer]
- # 获取数据源, 固定写法
- queryset = models.Book.objects.all()
- # 序列化类, 固定写法
- serializer_class = BookSerializer
这样, 浏览器再次访问, 接收到的就是普通的 JSON 格式数据, 而不是经过 DRF 格式化后的数据, renderer_classes 的查找逻辑与之前的解析器等等组件是完全一样的.
分页器
为了服务器性能考虑, 也为了用户体验, 我们不应该一次将所有的数据从数据库中查询出来, 返回给客户端浏览器, 如果数据量非常大, 这对于服务器来讲, 可以说是性能灾难, 而对于用户来讲, 加载速度将会非常慢.
而分页器能很好的解决该问题.
分页器的使用
第一步: 导入模块
from rest_framework.pagination import PageNumberPagination
第二步: 获取数据
books = Book.objects.all()
第三步: 创建分页器
paginater = PageNumberPagination()
第四步: 开始分页
paged_books = paginater.paginate_queryset(books, request)
第五步: 将分页后的数据进行序列化
serialized_data = BookSerializer(paged_books, many=True)
第六步: 返回数据
return Response(serialized_data.data)
常用参数介绍
常用分页器参数:
1. page_size: 用来控制每页显示多少条数据(全局参数名为 PAGE_SIZE);
2. page_query_param: 用来提供直接访问某页的数据;
3. page_size_query_param: 临时调整当前显示多少条数据
4. max_page_size: 控制 page_size_query_param 参数能调整的最大条数
偏移分页器参数
1. default_limit: 每页显示的数据条数
2. offset_query_param: 要偏移的标杆, 在前端以 get 的形式传, key 为 offset('可修改')
3. limit_query_param: 偏移量, 在前端以 get 的形式传, key 为 limit('可修改')
4. max_limit: 一页最大的显示条数
自定义分页器
常用分页器 url :
- # url: 示例
- http://http://127.0.0.1:8000/books/?page=2
- # 在第二页显示, 100 条, 但是 page_size 最大不能超过定义的 max_page_size
- http://http://127.0.0.1:8000/books/?page=2&page_size=100
常用分页器类:
- from rest_framework.pagination import PageNumberPagination
- # 定义分页器类
- class BookPageNumberPagination(PageNumberPagination):
- # 默认一页条数
- page_size = 2
- # 前端发送的页数关键字名
- page_query_param = 'page'
- # 用户自定义一页条数 关键字名
- page_size_query_param = 'page_size'
- # 用户自定义一页最大控制条数
- max_page_size = 2
偏移分页器 url :
- # url: 示例
- http://http://127.0.0.1:8000/books/?limit=10
- # 在 100 条后显示 10 条, 但是显示的条数不能超过定义的 max_limit
- http://http://127.0.0.1:8000/books/?limit=10&offset=100
偏移分页器类:
- from rest_framework.pagination import LimitOffsetPagination
- class BookLimitOffsetPagination(LimitOffsetPagination):
- # 默认一页条数
- default_limit = 2
- # 从 offset 开始往后显示 limit 条
- limit_query_param = 'limit'
- offset_query_param = 'offset'
- # 最大显示多少条
- max_limit = 4
视图类使用:
- class BookView(ModelViewSet):
- # 指定分页器类, 固定写法, 只能指定一个分页器类
- pagination_class = BookPageNumberPagination
- # pagination_class = BookLimitOffsetPagination
- # 获取数据源, 固定写法
- queryset = models.Book.objects.all()
- # 序列化类, 固定写法
- serializer_class = BookSerializer
- ~>.<~
来源: https://www.cnblogs.com/pungchur/p/12043539.html