Django框架(二十二)—— Django rest_framework-频率组件
频率组件
[TOC]
一、作用
为了控制用户对某个url请求的频率,比如,一分钟以内,只能访问三次
二、自定义频率类
# 写一个频率认证类
class MyThrottle:
visit_dic = {}
visit_time = None
def __init__(self):
self.ctime = time.time()
# 重写allow_request()方法
# request是request对象,view是视图类,可以对视图类进行操作
def allow_request(self, request, view):
'''
(1)取出访问者ip
(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
(3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
visit_dic = {ip1:[time2, time1, time0],
ip2:[time1, time0],
}
'''
# 取出访问者ip,ip可以从请求头中取出来
ip = request.META.get('REMOTE_ADDR')
# 判断该次请求的ip是否在地点中
if ip in self.visit_dic:
# 当存在字典中时,取出这个ip访问时间的列表
visit_time = self.visit_dic[ip]
self.visit_time = visit_time
while visit_time:
# 当访问时间列表中有值,时间间隔超过60,就将那个历史时间删除
if self.ctime - visit_time[-1] > 60:
visit_time.pop()
else:
# 当pop到一定时,时间间隔不大于60了,退出循环,此时得到的是60s内访问的时间记录
break
# while循环等价于
# while visit_time and ctime - visit_time[-1] > 60:
# visit_time.pop()
# 列表长度可表示访问次数,根据源码,可以得出,返回值是Boolean类型
if len(visit_time) >= 3:
return False
else:
# 如果60秒内访问次数小于3次,将当前访问的时间记录下来
visit_time.insert(0, self.ctime)
return True
else:
# 如果字典中没有当前访问ip,将ip加到字典中
self.visit_dic[ip] = [self.ctime, ]
return True
# 获取下次距访问的时间
def wait(self):
return 60 - (self.ctime - self.visit_time[-1])
# view层
from app01 import MyAuth
from rest_framework import exceptions
class Book(APIView):
# 局部使用频率控制
throttle_classes = [MyAuth.MyThrottle, ]
def get(self,request):
return HttpResponse('ok')
# 重写抛出异常的方法 throttled
def throttled(self, request, wait):
class MyThrottled(exceptions.Throttled):
default_detail = '下次访问'
extra_detail_singular = '还剩 {wait} 秒.'
extra_detail_plural = '还剩 {wait} 秒'
raise MyThrottled(wait)
三、内置的访问频率控制类
from rest_framework.throttling import SimpleRateThrottle
# 写一个频率控制类,继承SimpleRateThrottle类
class MyThrottle(SimpleRateThrottle):
# 配置scope,通过scope到setting中找到 3/m
scope = 'ttt'
def get_cache_key(self, request, view):
# 返回ip,效果和 get_ident() 方法相似
# ip = request.META.get('REMOTE_ADDR')
# return ip
# get_ident 返回的就是ip地址
return self.get_ident(request)
# view层视图类
class Book(APIView):
throttle_classes = [MyAuth.MyThrottle, ]
def get(self, request):
return HttpResponse('ok')
def throttled(self, request, wait):
class MyThrottled(exceptions.Throttled):
default_detail = '下次访问'
extra_detail_singular = '还剩 {wait} 秒.'
extra_detail_plural = '还剩 {wait} 秒'
raise MyThrottled(wait)
# setting中配置
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'ttt': '10/m'
}
}
- 因此,要实现10分钟允许访问六次,可以继承
SimpleRateThrottle类,然后重写parse_rate()方法,将duration中key对应的值改为自己需要的值
四、全局、局部使用
1、全局使用
在setting中配置
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': ['app01.MyAuth.MyThrottle', ],
}
2、局部使用
在视图类中重定义throttle_classes
throttle_classes = [MyAuth.MyThrottle, ]
3、局部禁用
在视图类中重定义throttle_classes为一个空列表
throttle_classes = []
五、源码分析
1、as_view -----> view ------> dispatch ------> initial ----> check_throttles 频率控制
2、self.check_throttles(request)
def check_throttles(self, request):
"""
Check if request should be throttled.
Raises an appropriate exception if the request is throttled.
"""
# (2-----1) get_throttles 由频率类产生的对象组成的列表
for throttle in self.get_throttles():
if not throttle.allow_request(request, self):
# (4)异常信息的处理
self.throttled(request, throttle.wait())
(2-----1) self.get_throttles()
def get_throttles(self):
"""
Instantiates and returns the list of throttles that this view uses.
"""
return [throttle() for throttle in self.throttle_classes]
3、allow_request()
自身、所在类找都没有,去父类中找
class SimpleRateThrottle(BaseThrottle):
cache = default_cache
timer = time.time
cache_format = 'throttle_%(scope)s_%(ident)s'
scope = None
THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
def __init__(self):
if not getattr(self, 'rate', None):
self.rate = self.get_rate()
self.num_requests, self.duration = self.parse_rate(self.rate)
def parse_rate(self, rate):
if rate is None:
return (None, None)
num, period = rate.split('/')
num_requests = int(num)
duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
return (num_requests, duration)
def allow_request(self, request, view):
if self.rate is None:
return True
# (3-----1) get_cache_key就是要重写的方法,若不重写,会直接抛出异常
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
self.history = self.cache.get(self.key, [])
self.now = self.timer()
# Drop any requests from the history which have now passed the
# throttle duration
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop()
if len(self.history) >= self.num_requests:
return self.throttle_failure()
return self.throttle_success()
# 返回距下一次能请求的时间
def wait(self):
"""
Returns the recommended next request time in seconds.
"""
if self.history:
remaining_duration = self.duration - (self.now - self.history[-1])
else:
remaining_duration = self.duration
(3-----1) self.get_cache_key(request, view)
def get_cache_key(self, request, view):
"""
Should return a unique cache-key which can be used for throttling.
Must be overridden.
May return `None` if the request should not be throttled.
"""
raise NotImplementedError('.get_cache_key() must be overridden')
4、self.throttled(request, throttle.wait()) --------> 抛出异常
def throttled(self, request, wait):
"""
If request is throttled, determine what kind of exception to raise.
"""
raise exceptions.Throttled(wait)
(4------1)raise exceptions.Throttled(wait) -------> 异常信息
class Throttled(APIException):
status_code = status.HTTP_429_TOO_MANY_REQUESTS
# 重写下面三个变量就可以修改显示的异常信息,例如用中文显示异常信息
default_detail = _('Request was throttled.')
extra_detail_singular = 'Expected available in {wait} second.'
extra_detail_plural = 'Expected available in {wait} seconds.'
default_code = 'throttled'
def __init__(self, wait=None, detail=None, code=None):
if detail is None:
detail = force_text(self.default_detail)
if wait is not None:
wait = math.ceil(wait)
detail = ' '.join((
detail,
force_text(ungettext(self.extra_detail_singular.format(wait=wait),
self.extra_detail_plural.format(wait=wait),
wait))))
self.wait = wait
super(Throttled, self).__init__(detail, code)
Django框架(二十二)—— Django rest_framework-频率组件的更多相关文章
- Django框架(十二)-- 中间件、CSRF跨站请求伪造
中间件 一.什么是中间件 请求的时候需要先经过中间件才能到达django后端(urls,views,templates,models) 响应的时候也需要经过中间件才能到达web服务网关接口 djang ...
- Django框架(十二)—— 补充:inclusion_tag、defer、only、choice、事务、创建多对多的第三张表
目录 补充:inclusion_tag.defer.only.choice.事务.创建多对多的第三张表 一.inclusion_tag 1.作用 2.使用 二.defer与only 1.定义 2.使用 ...
- Django框架(十二)-- Djang与Ajax
一.什么是Ajax AJAX(Asynchronous Javascript And XML)翻译成中文就是“异步Javascript和XML”.即使用Javascript语言与服务器进行异步交互,传 ...
- 潭州课堂25班:Ph201805201 django框架 第十二课 自定义中间件,上下文处理,admin后台 (课堂笔记)
中间件 在项目主目录下的配置文件 在项目主目录下创建文件 写个自定义异常处理 方法1 要让其生效,要在主目录下,的中间件中进行注册 主目录下.该文件名.类名 在进入视图函数之前进行判断, 给 req ...
- 第三百二十节,Django框架,生成二维码
第三百二十节,Django框架,生成二维码 用Python来生成二维码,需要qrcode模块,qrcode模块依赖Image 模块,所以首先安装这两个模块 生成二维码保存图片在本地 import qr ...
- WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇]
原文:WCF技术剖析之二十二: 深入剖析WCF底层异常处理框架实现原理[中篇] 在[上篇]中,我们分别站在消息交换和编程的角度介绍了SOAP Fault和FaultException异常.在服务执行过 ...
- Web 前端开发精华文章推荐(HTML5、CSS3、jQuery)【系列二十二】
<Web 前端开发精华文章推荐>2014年第一期(总第二十二期)和大家见面了.梦想天空博客关注 前端开发 技术,分享各类能够提升网站用户体验的优秀 jQuery 插件,展示前沿的 HTML ...
- 备忘录模式 Memento 快照模式 标记Token模式 行为型 设计模式(二十二)
备忘录模式 Memento 沿着脚印,走过你来时的路,回到原点. 苦海翻起爱恨 在世间难逃避命运 相亲竟不可接近 或我应该相信是缘份 一首<一生所爱>触动了多少 ...
- 二十二. Python基础(22)--继承
二十二. Python基础(22)--继承 ● 知识框架 ● 继承关系中self的指向 当一个对象调用一个方法时,这个方法的self形参会指向这个对象 class A: def get(s ...
- JAVA基础知识总结:一到二十二全部总结
>一: 一.软件开发的常识 1.什么是软件? 一系列按照特定顺序组织起来的计算机数据或者指令 常见的软件: 系统软件:Windows\Mac OS \Linux 应用软件:QQ,一系列的播放器( ...
随机推荐
- 目前写出的bug
要检测p->next 与p都不=NULL while(p->next!=NULL &&p!=NULL) 会导致访问access NULL pointer的runtime错误 ...
- Linux(Ubuntu)常用命令(五)—— vi/vim常用操作
vi/vim常用命令 vim其实就是vi的升级版,vi里的所有命令vim里都可以用,一般使用来说几乎没什么差别. 注:本篇文章区分大小写! vi / vim三级模式的关系: 命令行模式 任何时候,不管 ...
- Spring Boot 支持 HTTPS 如此简单,So easy!
这里讲的是 Spring Boot 内嵌式 Server 打 jar 包运行的方式,打 WAR 包部署的就不存在要 Spring Boot 支持 HTTPS 了,需要去外部对应的 Server 配置. ...
- FastReport.net 使用 Winform WebForm打印
delphi用的fastreport比较多 所以.net中也研究一下用法,这个打印控件还是很简单的 只要手动设计一下写少许代码就可以打印了 甚至可以写成通用代码 以后就可以不用写代码 安装demo会同 ...
- Linux中通过grep命令检索文件内容和指定内容前后几行
原文链接: https://www.linuxidc.com/Linux/2017-11/148390.htm Linux系统中搜索.查找文件中的内容,一般最常用的是grep命令,另外还有egrep命 ...
- [fw]PAGE_SIZE & PAGE_SHIFT & _AC()
PAGE_SIZE & PAGE_SHIFT & _AC() 在大多系统下,PAGE_SIZE被定义为 4k 大小,即 4096 字节. 在 x86 系统里,PAGE_SIZE 和 P ...
- React-Native实战项目-导航器篇(一)
前言:官方文档已经看了一遍,但印象不是很深,于是在mooc上找了个实战学习项目做一做. 本篇目录: 基础导航练习√ 1.ReactNavigation之createStackNavigator导航器案 ...
- linux c 链接详解2-定义和声明
2定义和声明 摘自:linux c编程一站式学习 可以学会extern和static用法,头文件知识. 2.1. extern和static关键字 在上一节我们把两个程序文件放在一起编译链接,main ...
- 2019牛客暑期多校训练营(第三场)I Median
题意:给出n-2的中位数序列b,b[i]代表原序列中(a[i],a[i+1],a[i+2])的中位数,求a. 解法:比赛的时候没做出来,赛后看题解的.解法跟网上各位大佬一样:首先要证明其实原序列a中的 ...
- config.properties
# 数据库配置db.host=10.100.2.50db.port=3306db.database=paycoredb.username=rootdb.password=mysql@123db.ini ...