六、Drf限流组件

六、限流组件

限制某个视图在某个时间段内被同一个用户访问的次数

6.1限流组件的简单应用

1)安装django-redis

pip3 install django-redis

2)在settings.py中注册cache

#缓存数据库redis配置
CACHES={
    "default":{
        "BACKEND":"django_redis.cache.RedisCache",
        "LOCATION":"redis://"+redis_host+":"+redis_port,            #redis主机地址和端口,数据在local_settings中
        "OPTIONS":{
            "CLIENT_CLASS":"django_redis.client.DefaultClient",
            "CONNECTION_POOL_KWARGS":{
                "max_connections":1000,
                "encoding":"utf-8"
            },
            "PASSWORD":redis_password                                #redis密码,数据在local_settings中
        }
    }
}

3)编写限流类

#ext.throttle

from rest_framework.throttling import SimpleRateThrottle
from django.core.cache import cache as default_cache

class Mythrottle(SimpleRateThrottle):
    scope='xxx'                         #限流名称,可自定义
    #限流策略('xxx'是scope,'5/m'代表每份钟访问次数不超过5次,s:1,m:60,h:60*60,d:60*60*24)
    THROTTLE_RATES = {'xxx':'5/m'}
	#这个cache其实就是上面在settings.py中注册的redis
    cache = default_cache
    
    def get_cache_key(self, request, view):
        #获取唯一标识
        if request.user:
            #如果是已登入用户,ident取用户id
            ident=request.user.pk
        else:
            #如果是未登入用户,ident取用户IP
            ident=self.get_ident(request)
        #返回格式化以后的唯一标识
        return self.cache_format % {'scope':self.scope,'ident':ident}

3)在视图中应用限流

class LoginView(MyAPIView):
    #用户登入,不需要认证,不需要任何权限
    authentication_classes = []
    permission_classes = []

    #应用限流
    throttle_classes = [Mythrottle,]
    def post(self,request):
        name=request.data.get('name')
        password=request.data.get('password')
        print(name,password)
        user_obj=models.User.objects.filter(name=name,password=password).first()
        if not user_obj:
            #用户名密码错误
            return Response({'status':False,'errMsg':'用户名或密码错误'})
        token=str(uuid.uuid4())
        user_obj.token=token
        user_obj.save()


        return Response({'status':True,'token':token})

4)效果

在这里插入图片描述

5)全局配置

#settings.py
REST_FRAMEWORK = {
    
    'DEFAULT_THROTTLE_RATES':{'xxx':'5/m','ooo':'3/m'},
}
#限流类
class Mythrottle(SimpleRateThrottle):
    #这个scope的值,必须在全局配置中已定义
    scope='xxx'
    这个THROTTLE_RATES在限流类中就不需要写了
    # THROTTLE_RATES = {'xxx':'5/m'}

    cache = default_cache

    def get_cache_key(self, request, view):
        if request.user:
            ident=request.user.pk
        else:
            ident=self.get_ident(request)
        return self.cache_format % {'scope':self.scope,'ident':ident}

6.2自定义错误信息

限流的错误信息实际上写在rest_framework.exceptions.Throttled中

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_str(self.default_detail)
        if wait is not None:
            wait = math.ceil(wait)
            detail = ' '.join((
                detail,
                force_str(ngettext(self.extra_detail_singular.format(wait=wait),
                                   self.extra_detail_plural.format(wait=wait),
                                   wait))))
        self.wait = wait
        super().__init__(detail, code)

因此我们只需要在执行限流时修改一下这里的错误信息即可

自定义一个类,继承APIView,并修改错误信息

from rest_framework import exceptions
from django.utils.translation import gettext_lazy as _
class MyAPIView(APIView):
    def __init__(self):
        exceptions.Throttled.default_detail = _('请求被限制,')
        exceptions.Throttled.extra_detail_singular = _('{wait}秒后可继续访问.')
        exceptions.Throttled.extra_detail_plural = _('{wait}秒后可继续访问.')

视图类继承上面创建的类MyAPIView

class LoginView(MyAPIView):
    #用户登入,不需要认证,不需要任何权限
    authentication_classes = []
    permission_classes = []

    #限流
    throttle_classes = [Mythrottle,]
    def post(self,request):
        name=request.data.get('name')
        password=request.data.get('password')
        print(name,password)
        user_obj=models.User.objects.filter(name=name,password=password).first()
        if not user_obj:
            #用户名密码错误
            return Response({'status':False,'errMsg':'用户名或密码错误'})
        token=str(uuid.uuid4())
        user_obj.token=token
        user_obj.save()


        return Response({'status':True,'token':token})

效果:

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暮毅

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值