zoukankan      html  css  js  c++  java
  • DRF Django REST framework 之 频率,响应器与分页器组件(六)

    频率组件

    频率组件类似于权限组件,它判断是否给予请求通过。频率指示临时状态,并用于控制客户端可以向API发出的请求的速率。

    与权限一样,可以使用多个调节器。API可能会对未经身份验证的请求进行限制,而对于经过身份验证的请求则进行限制较少。

    例如,可以将用户限制为每分钟最多60个请求,每天最多1000个请求。

    自定义频率组件

    使用方式与权限,认证组件几乎相同

    该方式没有DRF提供的方式简洁

    import time
    import math
    
    from rest_framework import exceptions
    
    
    class MyException(exceptions.Throttled):
        default_detail = '连接次数过多'
        extra_detail_plural = extra_detail_singular = '请在{wait}秒内访问'
    
        def __init__(self, wait=None, detail=None, code=None):
            super().__init__(wait=wait, detail=detail, code=code)
    
    
    class VisitThrottle():
        user_visit_information = dict()
        visited_times = 1
        period = 60
        allow_times_per_minute = 5
        first_time_visit = True
    
        def allow_request(self, request, view):
            self.request_host = request_host = request.META.get("REMOTE_ADDR")
            current_user_info = self.user_visit_information.get(request_host, None)
    
            if not self.__class__.first_time_visit:
                self.user_visit_information[request_host][0] += 1
                current_visit_times = self.user_visit_information[request_host][0]
    
                if current_visit_times > self.allow_times_per_minute:
                    if self._current_time - current_user_info[1] <= self.period:
                        if len(current_user_info) > 2:
                            current_user_info[2] = self._time_left
                        else:
                            current_user_info.append(self._time_left)
    
                        view.throttled = self.throttled
                        return None
                    else:
                        self.__class__.first_time_visit = True
    
            if self.first_time_visit:
                self.__class__.first_time_visit = False
                self._initial_infomation()
    
            return True
    
        def wait(self):
            return self.period - self.user_visit_information[self.request_host][2]
    
        def throttled(self, request, wait):
            raise MyException(wait=wait)
    
        @property
        def _current_time(self):
            return time.time()
    
        @property
        def _time_left(self):
            return math.floor(self._current_time - self.user_visit_information.get(self.request_host)[1])
    
        def _initial_infomation(self):
            self.user_visit_information[self.request_host] = [self.visited_times, self._current_time]

    基于每个视图设置频率:

    class BookView(ModelViewSet):# 指定频率类,固定写法
        throttle_classes = [RateThrottle]
        # 获取数据源, 固定写法
        queryset = models.Book.objects.all()
        # 序列化类, 固定写法
        serializer_class = BookSerializer

    使用DRF简单频率控制(局部)

    from rest_framework.throttling import SimpleRateThrottle
    
    
    class RateThrottle(SimpleRateThrottle):
        # 每分钟最多五次
        rate = '5/m'
    
        def get_cache_key(self, request, view):
            return self.get_ident(request)

    rate代表访问评率,上面表示每分钟五次, get_cache_key 是必须存在的,它的返回值告诉当前频率控制组件要使用什么方式区分访问者(比如ip地址)。

    在视图中使用:

    class BookView(ModelViewSet):
        # 指定频率类,固定写法
        throttle_classes = [RateThrottle]
        # 获取数据源, 固定写法
        queryset = models.Book.objects.all()
        # 序列化类, 固定写法
        serializer_class = BookSerializer

    全局频率控制

    首先定义一个频率控制类,并且必须继承 SimpleRateThrottle 这个类,它是DRF提供的一个方便的频率控制类,请看下面的代码:

    from rest_framework.throttling import SimpleRateThrottle
    
    
    class RateThrottle(SimpleRateThrottle):
        scope = "visit_rate"
    
        def get_cache_key(self, request, view):
            return self.get_ident(request)

    在全局配置频率控制参数:

    REST_FRAMEWORK = {
        "DEFAULT_THROTTLE_CLASSES": ('app.utils.throttles.RateThrottle',),
        "DEFAULT_THROTTLE_RATES": {
            "visit_rate": "5/m"
        }
    }

    这样就实现了,每分钟最多五次访问的逻辑。

    另外,可以使用 DEFAULT_THROTTLE_CLASSES 和 DEFAULT_THROTTLE_RATES 设置全局设置默认的限制策略。

    例如:

    REST_FRAMEWORK = {
        'DEFAULT_THROTTLE_CLASSES': [
            'rest_framework.throttling.AnonRateThrottle',
            'rest_framework.throttling.UserRateThrottle'
        ],
        'DEFAULT_THROTTLE_RATES': {
            # 游客每天访问次数不能超过100次
            'anon': '100/day',
            # 用户每天访问次数不能超过1000次
            'user': '1000/day'
        }
    }

    响应器

    在使用DRF的Response类来将数据响应给客户端时,不管是POSTMAN工具还是浏览器,都能浏览到经过格式化后的,清晰易懂数据,DRF是怎么做的呢?其实就是通过响应器组件

    响应器组件的使用

    如果不需要使用DRF提供给浏览器的格式化后的数据,只需要禁止该响应方式即可:

    from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer
    
    class BookView(ModelViewSet):
        # 指定响应器类,固定写法,返回json格式数据
        renderer_classes = [JSONRenderer]
        # 获取数据源, 固定写法
        queryset = models.Book.objects.all()
        # 序列化类, 固定写法
        serializer_class = BookSerializer

    这样,浏览器再次访问,接收到的就是普通的json格式数据,而不是经过DRF格式化后的数据,renderer_classes的查找逻辑与之前的解析器等等组件是完全一样的。

    分页器

    为了服务器性能考虑,也为了用户体验,我们不应该一次将所有的数据从数据库中查询出来,返回给客户端浏览器,如果数据量非常大,这对于服务器来讲,可以说是性能灾难,而对于用户来讲,加载速度将会非常慢。

    而分页器能很好的解决该问题。

    分页器的使用

    第一步:导入模块

    from rest_framework.pagination import PageNumberPagination

    第二步:获取数据

    books = Book.objects.all()

    第三步:创建分页器

    paginater = PageNumberPagination()

    第四步:开始分页

    paged_books = paginater.paginate_queryset(books, request)

    第五步:将分页后的数据进行序列化

    serialized_data = BookSerializer(paged_books, many=True)

    第六步:返回数据

    return Response(serialized_data.data)

    常用参数介绍

    常用分页器参数:
    1. page_size:        用来控制每页显示多少条数据(全局参数名为PAGE_SIZE);
    2. page_query_param:    用来提供直接访问某页的数据;
    3. page_size_query_param: 临时调整当前显示多少条数据
    4. max_page_size:       控制page_size_query_param参数能调整的最大条数
    
    偏移分页器参数
    1. default_limit:      每页显示的数据条数 
    2. offset_query_param:   要偏移的标杆,在前端以get的形式传,key为offset('可修改') 
    3. limit_query_param:   偏移量,在前端以get的形式传,key为limit('可修改') 
    4. max_limit:         一页最大的显示条数

    自定义分页器

    常用分页器 url :

    # url:示例
    http://http://127.0.0.1:8000/books/?page=2
    # 在第二页显示,100条,但是page_size最大不能超过定义的max_page_size
    http://http://127.0.0.1:8000/books/?page=2&page_size=100

    常用分页器类:

    from rest_framework.pagination import PageNumberPagination
    
    
    # 定义分页器类
    class BookPageNumberPagination(PageNumberPagination):
        # 默认一页条数
        page_size = 2
        # 前端发送的页数关键字名
        page_query_param = 'page'
        # 用户自定义一页条数 关键字名
        page_size_query_param = 'page_size'
        # 用户自定义一页最大控制条数
        max_page_size = 2

    偏移分页器 url :

    # url:示例
    http://http://127.0.0.1:8000/books/?limit=10
    # 在100条后显示10条, 但是显示的条数不能超过定义的max_limit
    http://http://127.0.0.1:8000/books/?limit=10&offset=100

    偏移分页器类:

    from rest_framework.pagination import LimitOffsetPagination
    
    
    class BookLimitOffsetPagination(LimitOffsetPagination):
        # 默认一页条数
        default_limit = 2
        # 从offset开始往后显示limit条
        limit_query_param = 'limit'
        offset_query_param = 'offset'
        # 最大显示多少条
        max_limit = 4

    视图类使用:

    class BookView(ModelViewSet):
        # 指定分页器类,固定写法,只能指定一个分页器类
        pagination_class = BookPageNumberPagination
        # pagination_class = BookLimitOffsetPagination
        # 获取数据源, 固定写法
        queryset = models.Book.objects.all()
        # 序列化类, 固定写法
        serializer_class = BookSerializer

    ~>.<~

  • 相关阅读:
    时序图
    用例图
    欢迎界面(闪屏)
    WBS
    闲来听书
    软件团队的模式
    结对编程
    在个人项目中,找bug,审核代码.
    时序图
    部分功能的实现
  • 原文地址:https://www.cnblogs.com/pungchur/p/12043539.html
Copyright © 2011-2022 走看看