drf -- 限流组件Throttling

限流组件Throttling

  • 可以对接口访问的频次进行限制,以减轻服务器压力,或者实现特定的业务。一般用于付费购买次数,投票等场景使用.

可选限流类

  • 1.AnonRateThrottle :限制所有匿名未认证用户,使用IP区分用户。
    • 使用DEFAULT_THROTTLE_RATES['anon'] 来设置频次
  • 2.UserRateThrottle:限制认证用户,使用User id 来区分。
    • 使用DEFAULT_THROTTLE_RATES['user'] 来设置频次

前两类的使用,在配置文件中配置,

x REST_FRAMEWORK = {    'DEFAULT_THROTTLE_CLASSES': ( # 启用的限制类        
                              'rest_framework.throttling.AnonRateThrottle',        
                              'rest_framework.throttling.UserRateThrottle'    ),    
                        'DEFAULT_THROTTLE_RATES': {   # 限制频率        
                                'anon': '100/day',        
                                'user': '1000/day'    
                        }
}

#DEFAULT_THROTTLE_RATES 可以使用 `second`, `minute`, `hour` 或`day`来指明周期,例如:

'DEFAULT_THROTTLE_RATES': {  # 限制频率
        'anon': '3/minute',
        'user': '10/minute',
        'access': '5/minute', # 这个是自定义限流的频率配置
    }

前两类的使用,在视图函数中配置

  • 可以在具体视图中通过throttle_classess属性来配置,如
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView

class ExampleView(APIView):
    throttle_classes = [UserRateThrottle,]
    ...
  • 3.ScopedRateThrottle :限制用户对于每个视图的访问频次,使用ip或user id
    • <1>.给对应的视图类的 throttle_scope类属性 定义一个名字
    • <2>.在配置文件中配置好
      -示例代码:
class ContactListView(APIView):
    throttle_scope = 'contacts'
    ...

class ContactDetailView(APIView):
    throttle_scope = 'contacts'
    ...

class UploadView(APIView):
    throttle_scope = 'uploads'
    ...
REST_FRAMEWORK = {
    'DEFAULT_THROTTLE_CLASSES': (
        'rest_framework.throttling.ScopedRateThrottle',
    ),
    'DEFAULT_THROTTLE_RATES': {
        'contacts': '1000/day',
        'uploads': '20/day'
    }
}

实例代码:

#全局配置中设置访问频率,settings.py代码:
REST_FRAMEWORK = {
    # 权限[全局配置,会被局部配置覆盖]
    # 'DEFAULT_PERMISSION_CLASSES': (
    #     'rest_framework.permissions.IsAuthenticated',
    # ),

    # 限流
    # 'DEFAULT_THROTTLE_CLASSES': (  # 全局启用的限制类
    #     'rest_framework.throttling.AnonRateThrottle', # 匿名用户,游客
    #     'rest_framework.throttling.UserRateThrottle'  # 登录用户
    # ),
    'DEFAULT_THROTTLE_RATES': {  # 限制频率
        'anon': '3/minute',
        'user': '10/minute',
        'access': '5/minute', # 这个是自定义限流的频率配置
    }
}

#视图代码:

from students.models import Student
from students.serializers import StudentModelSerializer
from rest_framework.viewsets import ModelViewSet
from rest_framework.permissions import AllowAny,IsAuthenticated,IsAuthenticatedOrReadOnly,IsAdminUser
from .permission import ISMingGe
from rest_framework.throttling import UserRateThrottle,AnonRateThrottle,ScopedRateThrottle
class Students8APIView(ModelViewSet):
    serializer_class = StudentModelSerializer
    queryset = Student.objects.all()
    # 权限配置
    permission_classes = [AllowAny]
    # 限流配置
    # throttle_classes = [AnonRateThrottle,UserRateThrottle]
    # 自定义限流配置
    throttle_classes = [ScopedRateThrottle]
    throttle_scope = 'access'

实例代码--限制用户提交数据的时间(5分钟可以提交一次数据)

代码示例:

from rest_framework.viewsets import ModelViewSet
from django_filters.rest_framework import DjangoFilterBackend
from django_filters import FilterSet,filters
from rest_framework.throttling import SimpleRateThrottle
from rest_framework import exceptions,status

from app01.serializers.news import NewsSerializer
from app01 import models
from app01 import status_code

#自定义限流错误
class ThrottledException(exceptions.APIException):
    status_code = status.HTTP_429_TOO_MANY_REQUESTS
    default_code = 'throttled'

#自定义限流类,需要继承SimpleRateThrottle类
class NewThrottle(SimpleRateThrottle):

    THROTTLE_RATES = {"user":"1/5m"}
    cache_format = 'throttle_%(scope)s_%(ident)s'
    scope = "user"

    def get_cache_key(self, request, view):
        '''设置该用户缓存的唯一标识'''
        ident = request.user.pk
        return self.cache_format % {'scope': self.scope, 'ident': ident}

    def parse_rate(self, rate):
        '''
        重写父类的该方法,可以自定义限速的条件,
        因为原方法中,只能设置  1/m(1分钟一次) ,不能设置 1/5m(5分钟一次)
        '''
        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[-1]]
        count = int(period[0:-1])
        return (num_requests, count * duration)
    def throttle_failure(self):
        wait = self.wait()
        detail = {
            "code":status_code.THROTTLE_ERROR,
            "error":"发布受限制,还需要等{}秒才能发布".format(wait)
        }
        raise ThrottledException(detail)
    def throttle_success(self):
        '''
        因为父类代码中,只要访问过该url就会被限速,
        在用户提交错误数据时,也被限速,所以将该方法默认都为通过,
        只有在用户提交数据成功,且保存数据成功后,才会被限速
        :return:
        '''
        return True

    def done(self):
        '''
        自定义的方法,
        防止用户提交数据错误时,也被限速,
        所以只有当用户提交数据成功时,才会调用次方法,才会被限速
        '''
        self.history.insert(0, self.now)  # 将当前时间插入到历史时间列表的第一个位置
        self.cache.set(self.key, self.history, self.duration)


#视图函数
class NewsView(ModelViewSet):

    filter_backends = [DjangoFilterBackend]
    filterset_class = NewsFilter
    serializer_class = NewsSerializer
    queryset = models.News.objects.filter(deleted=False).order_by("-id")

    throttle_classes = [NewThrottle(), ]
    def get_queryset(self):
        token = self.request.query_params.get("token")
        user_obj = models.UserInfo.objects.filter(token=token).first()
        queryset = self.queryset.filter(user=user_obj)
        return queryset

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)
        for throttle in self.get_throttles():
            throttle.done()

    def get_throttles(self):
        if self.request.method == "POST":
            return self.throttle_classes
        return []
posted @   志强爱璇璇  阅读(225)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
点击右上角即可分享
微信分享提示