一、频率限制

1、频率限制是做什么的

开放平台的API接口调用需要限制其频率,以节约服务器资源和避免恶意的频繁调用。

2、频率组件原理

DRF中的频率控制基本原理是基于访问次数和时间的,当然我们可以通过自己定义的方法来实现。
当我们请求进来,走到我们频率组件的时候,DRF内部会有一个字典来记录访问者的IP,
以这个访问者的IP为key,value为一个列表,存放访问者每次访问的时间,

{
IP1: [第三次访问时间,第二次访问时间,第一次访问时间],
IP2: [第三次访问时间,第二次访问时间,第一次访问时间],
}

把每次访问最新时间放入列表的最前面,记录成这样的一个数据结构

如果我们设置的是10秒内只能访问5次,

  -- 1,判断访问者的IP是否在这个请求IP的字典里

  -- 2,保证这个列表里都是最近10秒内的访问的时间
      判断当前请求时间和列表里最早的(也就是最后的)请求时间的差值
      如果差大于10秒,说明请求以及不是最近10秒内的,删除(最早的)最后一个时间,
      继续判断倒数第二个,直到差值小于10秒

  -- 3,判断列表的长度(即访问次数),是否大于我们设置的5次,
      如果大于就限流,否则放行,并把时间放入列表的最前面。

3、自定义频率组件的使用

ps:源码自己看吧,相信你看得懂的,跟认证、权限流程差不多的

1. 自定义频率限制类
from rest_framework import throttling
import time # 10秒内不能超过5次访问
class MyThrottle(throttling.BaseThrottle):
VISIT_RECORD = {} def __init__(self):
self.history = None def allow_request(self, request, view):
# 频率限制
# 获取用户ip
ip = request.META.get('REMOTE_ADDR')
now = time.time()
# 判断用户是否第一次访问
if ip not in self.VISIT_RECORD:
self.VISIT_RECORD[ip] = [now]
return True
# 拿到用户的访问记录列表
history = self.VISIT_RECORD[ip]
# 用于返回还有多久才能再次访问
self.history = history
# 把访问的时间插入访问记录列表
history.insert(0, now)
# 如果当前访问时间和最早的时间间隔超过10秒,删除最早的时间
while history and now - history[-1] > 10:
history.pop()
# 如果访问列表长度大于5,限制访问
if len(history) > 5:
return False
else:
return True def wait(self):
# 还有等多久才能访问
now = time.time()
return self.history[-1] + 10 - now 2. 视图
class TestView(APIView):
throttle_classes = [MyThrottle, ]
def get(self, request):
return Response("频率测试接口")

4、DRF的频率限制模块

1. DRF的频率限制模块有5个类(即5种限制方式)

2. SimpleRateThrottle
# 从源码中可以看出频率限制类必须要有allow_request和wait方法
# 注意在SimpleRateThrottle类里面已经有allow_request和wait方法
# 但是allow_request方法,还需要你重写一些额外的方法和属性 from rest_framework import throttling # 1分钟内不能超过5次
class MyVisit(throttling.SimpleRateThrottle):
scope = "MV" def get_cache_key(self, request, view):
# 这个方法的返回值应该是ip地址
return request.META.get('REMOTE_ADDR') 还必须要配置一些设置settings
REST_FRAMEWORK = {
# 频率限制的配置
"DEFAULT_THROTTLE_RATES": {
'MV': '5/m', # 速率配置每分钟不能超过5次访问,MV是scope定义的值,
} }
# 局部使用:在需要的视图中声明 throttle_classes = [MyVisit,]

# 全局设置
REST_FRAMEWORK = {
  # 频率限制的配置
  "DEFAULT_THROTTLE_CLASSES": ['utils.throttlings.MyVisit', ],
  "DEFAULT_THROTTLE_RATES": {
    'MV': '5/m',
  }
} 3. 其他
限制匿名用户
AnonRateThrottle VISIT_RECORD那个大字典的键:登录用户用主键,没有登录的用户用IP地址
UserRateThrottle 自己看。。
ScopedRateThrottle

二、DRF之分页

1、介绍

DRF的自带的分页器几乎能满足我们对分页的要求了,所以这里分页我们就直接使用DRF的分页,
用自定义的类继承DRF的分页类,然后重写一些我们需要的参数就好了。

2、PageNumberPagination分页类

0. 简介
看第n页,每页显示默认设置的数据数量 --> http://127.0.0.1:8000/book/?page=1
看第n页,每页显示n条数据 --> http://127.0.0.1:8000/book/?page=2&size=4 1. 分页类
class MyPagination(pagination.PageNumberPagination):
# 每页显示的数量
page_size = 2
# 每页显示的最大数量
max_page_size = 5
# 搜索的参数关键字,即 ?
page_query_param = 'page'
# 控制每页显示数量的关键字
page_size_query_param = 'size' 2. 在自定义视图中使用分页
class BookView(APIView):
def get(self, request):
queryset = Book.objects.all()
# 1.实例化分页器对象
paginator = MyPagination()
# 2.调用这个分页器类的分页方法,拿到分页后的数据
page_queryset = paginator.paginate_queryset(queryset, request)
# 3.把分页好的数据拿去序列化
ser_obj = BookSerializer(page_queryset, many=True) # 这样返回数据,可以在浏览器输入size参数设置每页显示的数据
# return Response(ser_obj.data) # 调用分页器的get_paginated_response方法 返回带上一页下一页的数据
# 使用这个方法后不能在浏览器输入size参数设置每页显示的数据了
return paginator.get_paginated_response(ser_obj.data) 3. 在DRF的提供的视图中使用分页
class BookView(generics.GenericAPIView, mixins.ListModelMixin):
queryset = Book.objects.all()
serializer_class = BookSerializer
# 配置分页器类
pagination_class = MyPagination def get(self, request):
return self.list(request)

3、LimitOffsetPagination分页类

0. 简介
从0开始取两条数据(1、2) --> http://127.0.0.1:8000/api/pagination/book/?limit=2
从第二条数据开始取两条数据(3、4) --> http://127.0.0.1:8000/api/pagination/book/?limit=2&offset=2 1. 分页类
class MyPagination(pagination.LimitOffsetPagination):
# 从哪里开始拿数据
offset_query_param = 'offset'
# 拿多少条数据
limit_query_param = 'limit'
# 默认拿多少条数据
default_limit = 2
# 最多拿多少条
max_limit = 5 2. 在自定义视图或者DRF提供的视图中使用分页
跟上面使用方法一致。

4、CursorPagination分页类

0. 简介
按xx的顺序(倒序)显示xx条数据 --> http://127.0.0.1:8000/api/pagination/book/
上一页下一页是的值是随机字符串,每页显示3条数据 --> http://127.0.0.1:8000/api/pagination/book/?cursor=cD01&size=3 1. 分页类
class MyPagination(pagination.CursorPagination):
cursor_query_param = 'cursor'
# 每页显示的数量的搜索关键字
page_size_query_param = 'size'
# 每页显示的数据数量
page_size = 3
# 每页最大显示的数据数量
max_page_size = 5
# 按id的倒序显示
ordering = '-id' 2. 在自定义视图或者DRF提供的视图中使用分页
跟上面使用方法一致。

三、解析器

1、介绍

解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己想要的数据类型的过程。
本质就是对请求体中的数据进行解析。
请求头中的Content-Type告诉我们传过来的是什么类型的数据,我们就找自己的解析器,看有没有对应的解析器。

2、Django的解析器

请求进来的时候,请求体中的数据在request.body中,说明,解析器会把解析好的数据放入request.body,
我们在视图中可以打印request的类型,就能够发现request是WSGIRequest这个类。

那我们是怎么拿到request.POST数据的?

application/x-www-form-urlencoded只能上传文本格式的文件,
multipart/form-data是将文件以二进制的形式上传,这样可以实现多种类型的文件上传
一个解析到request.POST,一个解析到request.FILES中。

也就是说我们之前能在request中能到的各种数据是因为用了不同格式的数据解析器

3、DRF的解析器

在DRF框架中,解析器在request.data拿数据的时候会被调用,
也就是说DRF框架,请求数据都在request.data中,那我们看下这个Request类里的data

小结:
DRF解析器
'DEFAULT_PARSER_CLASSES': (
  'rest_framework.parsers.JSONParser',
  'rest_framework.parsers.FormParser',
  'rest_framework.parsers.MultiPartParser'
)

-- 原理:
  拿到我们配置的所有的解析器类的实例化对象
  通过ContentType跟解析器的media_type进行匹配
  匹配成功把解析器类实例化对象返回
  调用解析器类的parse方法去解析数据
  把解析好的数据返回

可以在我们的视图中配置视图级别的解析器

from rest_framework.parsers import JSONParser
from rest_framework.parsers import FormParser
from rest_framework.parsers import MultiPartParser class TestView(generics.GenericAPIView, mixins.ListModelMixin):
# 如果我只配置了两个解析器,那么这个视图就只能解析这两种格式
# 不在视图配置,就默认使用全局的三种解析器
parser_classes = [JSONParser, FormParser,]
def get(self, request):
return self.list(request)

四、渲染器

渲染器就是把数据有格式的、友好地展示出来

DRF给我们提供的渲染器有
'DEFAULT_RENDERER_CLASSES': (
  'rest_framework.renderers.JSONRenderer',
  'rest_framework.renderers.BrowsableAPIRenderer',
),

我们在浏览器中展示的DRF测试的页面,就是通过浏览器的渲染器来做的
当然我们可以展示Json数据类型,渲染器比较简单

DRF之频率限制、分页、解析器和渲染器的更多相关文章

  1. Restful API学习Day5 - DRF之限制 分页 解析器和渲染器

    参考文档: Django REST framework基础:认证.权限.限制 Django REST framework基础:分页 Django REST framework基础:解析器和渲染器 一. ...

  2. DRF 版本、认证、权限、限制、解析器和渲染器

    目录 一.DRF之版本控制 为什么要有版本控制? DRF提供的版本控制方案 版本的使用 全局配置 局部配置(使用较少) 二.DRF之认证 内置的认证 步骤 三.DRF之权限 1.自定义一个权限类 2. ...

  3. Django-Rest-Framework的解析器和渲染器

    Django-Rest-Framework的解析器和渲染器  restful framework 解析器 解析器的作用就是服务端接收客户端传来的数据,把数据解析成自己想要的数据类型的过程 本质就是对请 ...

  4. Django REST framework - 解析器和渲染器

    目录 Django REST framework - 解析器和渲染器 解析器 Django中的数据解析 DRF中的解析器 渲染器 Django REST framework - 解析器和渲染器 解析器 ...

  5. DRF频率、分页、解析器、渲染器

    DRF的频率 频率限制是做什么的 开放平台的API接口调用需要限制其频率,以节约服务器资源和避免恶意的频繁调用. 频率组件原理 DRF中的频率控制基本原理是基于访问次数和时间的,当然我们可以通过自己定 ...

  6. rest-framework框架——解析器、ur控制、分页、响应器、渲染器、版本

    一.解析器(parser) 解析器在reqest.data取值的时候才执行. 对请求的数据进行解析:是针对请求体进行解析的.表示服务器可以解析的数据格式的种类. from rest_framework ...

  7. Django-rest-framework 接口实现 分页:(Pagination) 解析器(Parser) 渲染器(renderer)

    分页:(Pagination) rest_framework 中已经定义好了 3 种 分页模式 from rest_framework.pagination import PageNumberPagi ...

  8. DRF 解析器和渲染器

    一,DRF 解析器 根据请求头 content-type 选择对应的解析器就请求体内容进行处理. 1. 仅处理请求头content-type为application/json的请求体 from dja ...

  9. DRF的解析器和渲染器

    解析器 解析器的作用 解析器的作用就是服务端接收客户端传过来的数据,把数据解析成自己可以处理的数据.本质就是对请求体中的数据进行解析. 在了解解析器之前,我们要先知道Accept以及ContentTy ...

随机推荐

  1. js中的new()到底做了些什么??

    要创建 Person 的新实例,必须使用 new 操作符.以这种方式调用构造函数实际上会经历以下 4个步骤:(1) 创建一个新对象:(2) 将构造函数的作用域赋给新对象(因此 this 就指向了这个新 ...

  2. Shell基础命令(一)

    Shell 教程 Shell 是一个用 C 语言编写的程序,它是用户使用 Linux 的桥梁.Shell 既是一种命令语言,又是一种程序设计语言. Shell 是指一种应用程序,这个应用程序提供了一个 ...

  3. iOS-----------关于UDID

    最近看友盟的SDK更新日志:(设备系统的正常升级不会改变OpenUDID) Apple公司于2013年5月1日开始,拒绝采集UDID的App上架App Store. 为适应Apple公司的这一政策,2 ...

  4. python 类继承演示范例的代码

    把做工程过程重要的代码片段备份一次,下面的资料是关于python 类继承演示范例的代码. # a simple example of a class inheritance # tested with ...

  5. Django数据库--事务及事务回滚

    数据库的读写操作中,事务在保证数据的安全性和一致性方面起着关键的作用,而回滚正是这里面的核心操作.Django的ORM在事务方面也提供了不少的API.有事务出错的整体回滚操作,也有基于保存点的部分回滚 ...

  6. java基础知识总结一:

      四种内部类 直接抛出异常 单例模式: 懒汉式单例.饿汉式单例.登记式单例     []关于内部类:  []关于异常: 直接捕捉并抛出异常:不需要给异常添加名字: if(i>10)throw ...

  7. 通过Visual Studio 2012 比较SQL Server 数据库的架构变更

    一 需求 随着公司业务的发展,数据库实例也逐渐增多,数据库也会越来越多,有时候我们会发现正式生产数据库也测试数据库数据不一致,也有可能是预发布环境下的数据库与其他数据库架构不一致,或者,分布式数据库上 ...

  8. MS SQL自定义函数IsNumeric

    判断字符串是否为纯数字,负数不算.如'00012','54585','1000' SET ANSI_NULLS ON GO SET QUOTED_IDENTIFIER ON GO CREATE FUN ...

  9. javascript基础之函数

    javascript的函数定义与python有很大的区别,的记住格式就好,下面请看代码 // 函数 // 简单定义 function func() { console.log('hello word' ...

  10. 报错:[Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the prop's value. Prop bei

    项目中遇到父组件传值 activeIndex <Tabs :tabs="tabs" :activeIndex="activeIndex" >< ...