Django框架(二十一)--Django rest_framework-频率组件

一、作用

为了控制用户对某个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)

原文地址:https://www.cnblogs.com/zhangbingsheng/p/10721001.html

时间: 2024-10-14 01:26:04

Django框架(二十一)--Django rest_framework-频率组件的相关文章

rest_framework频率组件

rest_framework频率组件能够限制一定时间内访问次数 rest_framework频率组件的使用 第一步,写一个类,继承SimpleRateThrottle,(根据ip限制) from rest_framework.throttling import SimpleRateThrottle class VisitThrottle(SimpleRateThrottle): scope = 'peter' def get_cache_key(self, request, view): ret

django框架&lt;二&gt;

django框架:   Models 1.基本创建 Django提供了一个抽象层("Model")的构建和管理Web应用程序的数据. Django使用一种新的方式,即:关系对象映射(Object Relational Mapping,简称ORM). 每个模型是一个Python类,子类django.db.models.model 模型中的每个属性代表一个数据库字段. # DEMO class Student(models.Model): name = models.CharField(m

Django 框架篇: 一. Django介绍; 二. 安装; 三. 创建项目;

一. web框架:   框架,即framework,特指为解决一个开放性问题而设计的具有一定约束性的支撑结构,使用框架可以帮你快速开发特定的系统,简单地说,就是你用别人搭建好的舞台来做表演. 对于所有的Web应用,本质上其实就是一个socket服务端,用户的浏览器其实就是一个socket客户端. import socket def handle_request(client): buf = client.recv(1024) client.send("HTTP/1.1 200 OK\r\n\r\

Django 框架篇(九): Django中的Form 组件

Django中的Form组件,帮我们处理了 form表单中的校验, 和错误提示的处理: 主要功能: 生成页面可用的HTML标签 对用户提交的数据进行校验 保留上次输入内容 使用form组件实现注册功能 1.  定义一个类, 继承django中的 forms.Form 代码实例: from django import forms # 按照Django form组件的要求自己写一个类 class RegForm(forms.Form): name = forms.CharField(label="用

Django框架(十六)—— forms组件、局部钩子、全局钩子

forms组件.局部钩子.全局钩子 一.什么是forms组件 forms组件就是一个类,可以检测前端传来的数据,是否合法. 例如,前端传来的邮箱数据,判断邮件格式对不对,用户名中不能以什么开头,等等 二.forms组件的使用 1.使用语法 from django.shortcuts import render, HttpResponse from django import forms # 1.先写一个类,继承Form class MyForm(forms.Form): # 定义一个属性,可以用

Django框架(十四)-- forms组件、局部钩子、全局钩子

一.什么是forms组件 forms组件就是一个类,可以检测前端传来的数据,是否合法. 例如,前端传来的邮箱数据,判断邮件格式对不对,用户名中不能以什么开头,等等 二.forms组件的使用 1.使用语法 from django.shortcuts import render, HttpResponse from django import forms # 1.先写一个类,继承Form class MyForm(forms.Form): # 定义一个属性,可以用来校验字符串类型 # 限制最大长度是

Django框架(二)

一:Django项目创建步骤: 方式1:命令创建: 进入指定目录 C:\Users\bing>F: F:\>cd mysite F:\mysite>django-admin startproject mysite F:\mysite>python manage.py startapp app01 F:\mysite>python manage.py startapp app02 F:\mysite>python manage.py startapp app03(一个Dj

Django框架(二):设计模型

1. 设计模型 我们之前操作数据库是通过写sql语句,那么能不能不写sql语句就可以操作数据库呢? 当然可以,这就要使用ORM框架了. 1.1 ORM框架 O是object,也就类对象的意思,R是relation,翻译成中文是关系,也就是关系数据库中数据表的意思,M是mapping,是映射的意思.在ORM框架中,它帮我们把类和数据表进行了一个映射,可以让我们通过类和类对象就能操作它所对应的表格中的数据.ORM框架还有一个功能,它可以根据我们设计的类自动帮我们生成数据库中的表格,省去了我们自己建表

简单Django框架推导及Django安装介绍

小结 软件开发架构 c/s 架构 客户端 服务端 b/s 架构 浏览器 服务端 HTTP协议:超文本传输协议 四大特性 基于TCP/IP之上作用于应用层 基于请求响应 无状态(不保存状态,每次请求都认为是陌生的请求) 无连接 (一旦数据交互完成就断开连接) 对比:长连接(websocket(HTTP协议大补丁) 数据格式 请求格式: ? 请求首行(请求方式,协议版本......) ? 请求头(一大堆k:v键值对) ? \r\n ? 请求体(真正的数据 ,发post请求的时候才有,如果是get请求

Django框架进阶7 django请求生命周期流程图, django中间件, csrf跨站请求伪造, auth认证模块

django请求生命周期流程图 djang中间件 它是django的门户 只要是全局相关的功能你都应该考虑使用django中间件来帮你完成 全局用户身份校验 全局用户访问频率校验 用户访问黑名单 用户访问白名单 # 只要以后用django开发业务 设计到全局相关的功能 你就考虑用中间件 MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'django.contrib.sessions.middleware.Sessio