1 频率类
2 视图类
3 路由
4 频率源码分析
'''
# 写限制逻辑
# (1)取出访问者ip
# (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,
在字典里,继续往下走
# (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,
把这种数据pop掉,这样列表中只有60s以内的访问时间,
# (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,
返回True,顺利通过
# (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
# return False
# 频率类写好,配置在视图类上,就会走它
'''
class MyThrottle(BaseThrottle):
VISIT_RECORD = {}
def __init__(self):
self.history = []
def allow_request(self, request, view):
# 写限制逻辑
# (1)取出访问者ip
ip = request.META.get('REMOTE_ADDR')
import time
ctime = time.time()
# (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,
# 表示第一次访问,在字典里,继续往下走
if ip not in self.VISIT_RECORD:
self.VISIT_RECORD[ip] = [ctime, ]
return True
# (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,
# 把这种数据pop掉,这样列表中只有60s以内的访问时间,
self.history = self.VISIT_RECORD[ip]
while self.history and ctime - self.history[-1] > 60:
self.history.pop()
# (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
if len(self.history) < 3:
self.history.insert(0, ctime)
return True
# (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
# return False
# 频率类写好,配置在视图类上,就会走它
return False
def wait(self):
import time
ctime = time.time()
return 60 - (ctime - self.history[-1])
from rest_framework.viewsets import GenericViewSet
from .throttling import MyThrottle
class BookView(GenericViewSet):
throttle_classes = [MyThrottle]
def list(self, request):
print(self.request)
return Response('测试自定义频率')
from django.contrib import admin
from django.urls import path
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('books', BookView, 'books')
urlpatterns = [
path('admin/', admin.site.urls),
]
urlpatterns += router.urls
# 1 频率源码
-APIView----disaptch---》self.initial(request, *args, **kwargs)---》416行:self.check_throttles(request)----》352行 check_throttles
def check_throttles(self, request):
# self.get_throttles()就是咱们配置在视图类上频率类的对象列表[频率类对象,]
for throttle in self.get_throttles():
# 执行频率类对象的allow_request,传了2个,返回True或False
if not throttle.allow_request(request, self):
# 反会给前端失败,显示还剩多长时间能再访问
throttle_durations.append(throttle.wait())
# 2 频率类要写
1 写一个类,继承,BaseThrottle
2 在类中重写:allow_request方法,传入 3个参数
3 在allow_request写限制逻辑,如果还能访问--》返回True
4 如果超了次数,就不能访问,返回False
5 局部配置在视图类上
6 全局配置在配置文件中
# 3 我们在drf中写的时候,不需要继承 BaseThrottle,继承了SimpleRateThrottle,重写get_cache_key
-我们猜测:一定是 SimpleRateThrottle帮咱们写了咱们需要写的
# 4 自定义频率类,实现一分钟只能访问三次的控制:
# (1)取出访问者ip
# (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
# (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
# (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
# (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
#5 SimpleRateThrottle 源码分析
- SimpleRateThrottle内部一定有:allow_request---》
def allow_request(self, request, view):
# 咱们没写,以后咱们可以在频率类中直接写
# rate='3/m' 以后不用写scope了,就会按一分钟访问3次现在
if self.rate is None:
return True
# 取出:重写的get_cache_key返回的值,咱们返回了访问者ip
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
# 根据当前访问者ip,取出 这个人的访问时间列表 [访问时间1,访问2,访问3,访问4]
self.history = self.cache.get(self.key, [])
# 取出当前时间
self.now = self.timer()
# 把访问时间列表中超过 限制时间外的时间剔除
while self.history and self.history[-1] <= self.now - self.duration:
self.history.pop()
# 判断访问时间列表是否大于 3
if len(self.history) >= self.num_requests:
return self.throttle_failure()
return self.throttle_success()