首页 > 其他分享 >drf之频率类,分页,排序,过滤

drf之频率类,分页,排序,过滤

时间:2022-10-10 22:34:27浏览次数:59  
标签:分页 self history rate 过滤 time 排序 class drf


一、自定义频率类

# 我们之前写的频率类其实是可以继承两个的SimpleRateThrottle, BaseThrottle

# 只不过现继承BaseThrottle需要重写BaseThrottle方法 我们现在按照继承BaseThrottle然后自定义频率

class MyThrottling(BaseThrottle):
    # 自定义的逻辑  {ip:[时间1,时间2]}
    time_dic = {}

    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        pass
        # (1)取出访问者ip
        ip = request.META.get('REMOTE_ADDR')
        # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
        import time
        now_time = time.time()
        if ip not in self.time_dic:
            self.time_dic[ip] = [now_time, ]
            return True
        self.history = self.time_dic.get(ip)
        # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
        while self.history and now_time - self.history[-1] > 60:
            self.history.pop()
        # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
        if len(self.history) < 3:
            self.history.insert(0, now_time)
            return True
        # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
        else:
            return False
# 然后在视图类中配置即可 但是现在错误信息不是中文的 需要重写wait方法才能显示中文
    def wait(self):
        import time
        now_time = time.time()
        return 60 - (now_time - self.history[-1])  # 用当前时间减去列表中最后一个时间 就是剩余时间

 二、频率类源码分析

# 我们在继承了SimpleRateThrottle类 然后在写频率类 其实就是这个帮我们写了allow_request方法所以我们去看看这个源码写了啥

    def allow_request(self, request, view):
        if self.rate is None:  # 首先判断了self.rate是否有值 rate在实例化对象的时候就已经赋值了 所以肯定有值
            return True
        self.key = self.get_cache_key(request, view)  
        # get_cache_key就是我们自己写的频率类重新写的方法 然后我们返回了用户的ip作为频率的限制 所以我们返回什么就以什么作为频率的限制
        if self.key is None:  # 所以这里为True做if判断
            return True  # 这里其实就是没有频率的限制 直接往下走
        self.history = self.cache.get(self.key, [])  # 通过缓存取出列表中用户ip的时间
        self.now = self.timer()  # 这个就是获取当前时间 self.timer()其实就是time.time
        while self.history and self.history[-1] <= self.now - self.duration:
            # 然后循环判断列表中是否有值, self.history就是列表最后一个时间就是最早的时间  
            # self.now就是当前时间  self.duration 就是我们配置的60
            # 然后如果最早的时间如果小于 当前时间减去我们配置的时间那么 就要把最早的时间给pop掉
            # 这样列表中就只剩下小于我们配置的时间
            self.history.pop()
        if len(self.history) >= self.num_requests:  # 然后在计算列表中小于我们配置的时间 是否大于我们配置的频率次数
            # 如果大于那么就要返回False
            return self.throttle_failure()  # 这里点进去其实就是返回了False  为了扩展性
            # 否则返回True
        return self.throttle_success()  
        
    def throttle_success(self):
        self.history.insert(0, self.now)  # 这个就是把当前时间插入到列表的开头
        self.cache.set(self.key, self.history, self.duration)  # 然后保存到缓存当中
        return True  # 返回True 就是没有限制

SimpleRateThrottle类

class SimpleRateThrottle(BaseThrottle):
    timer = time.time
    THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
    def __init__(self):
        if not getattr(self, 'rate', None):  
        # 这里就是使用反射判断我们写的类中是否有rate方法 我们肯定没写 所以if判断为True 就会走这个判断
            self.rate = self.get_rate()  
            # 然后self.rate有等于了self.get_rate() 所以我们根据查找顺序 要找到了该类下的get_rate方法 
            # 然后该方法返回了'3/m' 
        self.num_requests, self.duration = self.parse_rate(self.rate)  
        # 先执行了self.parse_rate方法 根据名字的查找顺序 最后还是在该类中找的该方法 然后该方法返回了3和60
        # 所以self.num_requests等于3  self.duration等于60
        # 这样就实例化完了

get_rate方法

        def get_rate(self):
        if not getattr(self, 'scope', None):  
        # 利用反射判断我们写的频率类中是否有scope方法或属性 我们是写的了所以if结果为False 所以不会走该if
            msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
                   self.__class__.__name__)  
            raise ImproperlyConfigured(msg)  # 如果没写就会抛异常  所以一定要写scope属性
        try:
            return self.THROTTLE_RATES[self.scope] # self.scope就是我们自己写的频率类中写的scope属性'luffy' 
            # THROTTLE_RATES根据上面的赋值其实就是这个就是我们在配置文件中配置的'DEFAULT_THROTTLE_RATES': {'luffy': '3/m'}字典
            # 然后根据字典取值把'3/m'返回出去 
        except KeyError:
            msg = "No default throttle rate set for '%s' scope" % self.scope
            raise ImproperlyConfigured(msg)

parse_rate

        def parse_rate(self, rate):  # rate就是传进来的 '3/m'
        if rate is None:  # 所以rate肯定有值
            return (None, None)  # 没有就返回两个None
        num, period = rate.split('/')  # 然后根据 / 切割字符串'3/m'
        # 然后有通过解压赋值 num=字符串的3, period=m
        num_requests = int(num)  # 将字符串的3转换为整型3 赋值给num_requests
        duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]  # period[0] 就是取出字符串索引为0的数据 那就是m
        # 这个就是 duration = {} 然后duration['m']  是一样的
        # 然后通过字典的取值方法 取出k为m的Value  所以duration就是60
        return (num_requests, duration)  # 然后把3和60返回出去

总结

  # 总结:以后要再写频率类,只需要继承SimpleRateThrottle,重写get_cache_key,配置类属性scope,配置文件中配置一下就可以了

三、分页功能

# 分页功能就只有获取全部的接口才会有分页,其他接口是没有分页功能的
# 然后后端的分页写法是固定的,只有前端展示的不一样而已
    eg:
        -pc端的上一页和下一页的点击
        -app的上拉和下滑都是分页的功能

# drf的分页使用

    -所以写一个类,然后继承drf提供的三个分页类之一
    -然后配置属性
    -然后在视图类中,视图类必须要继承GenericAPIView+ListModelMixin的子视图类上 因为只有GenericAPIView类有pagination_class属性
    -如果继承的是APIView,需要自己写
        page = MyPageNumberPagination()
        res = page.paginate_queryset(qs, request)

代码演示

1.PageNumberPagination

# 自己写的分页类  
class MyPageNumberPagination(PageNumberPagination):
    page_size = 2  # 每页展示2条数据
    page_query_param = 'page'  # 路径按照这样传入  books/?page=1  查询第几页
    page_size_query_param = 'size'  # 路径还可以这样写  books/?page=3&size=4  查询第三页,该页显示4条数据
    max_page_size = 5  # size后面如果超出5 那么该页就按照5条数据显示,没有超出就按照写的条数显示


# 视图类配置
class BooksView(ViewSetMixin, GenericAPIView, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = MyPageNumberPagination  # 在该类属性配置即可

# 然后通过 http://127.0.0.1:8000/books/?page=1路径即可访问第一页的数据

 2.LimitOffsetPagination

class MyLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 2  # 每页显示的条数
    limit_query_param = 'limit'  # 路径按照这样传入 books/?limit=4  这一页显示4条数据
    offset_query_param = 'offset'  # 路径还可以这样写  books/?offset=3&limit=4  # 我从第三条开始,然后取四条数据
    max_limit = 5  # limit后面如果超出5 那么该页就按照5条数据显示,没有超出就按照写的条数显示


# 视图类
class BooksView(ViewSetMixin, GenericAPIView, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = MyLimitOffsetPagination  # 因为分页只能是一种方式 所以只需要替换即可

# 然后就可以根据这个路径访问了 http://127.0.0.1:8000/books/?offset=3&limit=3

 

 3.CursorPagination

class MyCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'
    page_size = 2  # 每页显示的条数
    ordering = 'id'  # 按照表中的某个字段排序 我们按照id排序 加负号就是降序


# 试图类
class BooksView(ViewSetMixin, GenericAPIView, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = MyCursorPagination

# 这种分页方式 虽然不能跳到某一页 但是这种是效率最高的  适合大数据分页

 

 四、排序功能

# 排序肯定也是 只有获取全部的接口需要排序

# 排序功能drf提供了给我们有排序类
from rest_framework.filters import OrderingFilter

使用

class BooksView(ViewSetMixin, GenericAPIView, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    pagination_class = MyCursorPagination
    # 排序类的配置
    filter_backends = [OrderingFilter, ]  # 可以放多个
    # 指定那个字段排序
    ordering_fields = ['id', 'price']  # 按照id排序也可以按照price排序


# 排序还可以跟分页一起使用 但是是先排序后分页

 

 五、过滤功能

# 过滤功能也是一样的 只有获取全部需要过滤 其他接口不需要过滤
# restful规范中有一条,请求地址中带过滤条件:分页,排序,过滤统称为过滤
# 使用内置过滤类使用步骤   查询所有才涉及到排序,其它接口都不需要

# 必须是继承GenericAPIView+ListModelMixin的子视图类上

使用

from rest_framework.filters import SearchFilter

class BooksView(ViewSetMixin, GenericAPIView, ListModelMixin):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # 过滤类的配置
    filter_backends = [SearchFilter, ]  # 这个因为是列表 所以可以跟排序一起使用 ,因为排序和过滤的类属性是一起的
    # 指定那个字段过滤
    search_fields = ['title']  # 使用那个字段过滤



# 过滤也是可以跟分页一起使用的 只不过先过滤在分页

 

标签:分页,self,history,rate,过滤,time,排序,class,drf
From: https://www.cnblogs.com/stephenwzh/p/16777374.html

相关文章

  • 自定义频率类,分页,排序,过滤
    自定义频率类fromrest_framework.throttlingimportBaseThrottleclassMyThrottle(BaseThrottle):VISIT_RECORD={}#存放用户访问记录{ip1:[时间1,时间2],ip2:......
  • 【Django-rest-framework框架】 第08回 自定义频率类,分页功能,排序功能,过滤功能
    目录1.自定义频率类2.频率功能源码剖析3.分页功能3.1PageNumberPagination3.2LimitOffsetPagination3.3CursorPagination3.4drf中分页的使用4.排序功能5.过滤功能......
  • 自定义频率类,频率功能源码剖析,分页功能,排序功能,过滤功能
    1.自定义频率类继承BaseThrottle必须要重写allow_request方法,不然会报错classOurThrottle(SimpleRateThrottle):scope='ss'defget_cache_key(self,requ......
  • 【2022.10.10】drf(8)
    今日学习内容1.自定义评率类2.频率功能源码剖析3.分页功能4.排序功能5.过滤功能5.1内置过滤1自定义频率类fromrest_framework.throttlingimportBaseThr......
  • drf-频率类及分页排过滤序
    1自定义频率类取出访问者ip判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走循环判断当前ip的列表,有值,并且当前时间减去列表的最......
  • DRF
    DRF频率类#某个接口,限制访问频率----》可以根据IP,用户id#频率类的编写-第一步:写一个类,继承SimpleRateThrottle-第二步:重写get_cache_key方法-第三步:返......
  • drf 之分页,过滤,排序
    自定义频率类classMyThrottle(SimpleRateThrottle):VISIT_RECORD={}#存放用户访问记录{ip1:[时间1,时间2].。。}def__init__(self):self.hi......
  • 002 冒泡排序
    //冒泡排序从右缩小范围最小值放在最右边publicstaticvoidbubbleSort(int[]arr){if(arr==null||arr.length<2){return;......
  • 003 插入排序
    //插入排序从左扩大范围最小值放在最右边publicstaticvoidinsertionSort(int[]arr){if(arr==null||arr.length<2){return;......
  • 优先级排序为:算术运算符 > 关系运算符 > 赋值运算。
    优先级排序为:算术运算符>关系运算符>赋值运算。算术运算符中,-负数(如–1)、%百分比、^乘方、*和/(乘和除)、+和–(加和减)属于优先级第三级,加法运算符【+】、减法......