zoukankan      html  css  js  c++  java
  • Django高级篇四。restful的频率控制,分页方法,路由控制,版本控制

    一、rest-framework之频率控制

    为了控制用户对某个url请求的频率,比如,一分钟以内,只能访问三次

    1)自定义模式,其他框架调使用也是如此

    自定义频率逻辑

    # (1)取出访问者ip
    # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
    # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
    # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
    # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败

    代码实现

    class MyThro():
        VISIT_RECORD = {}
        def __init__(self):
            self.history=None
        def allow_request(self,request, view):
            #(1)取出访问者ip
            # print(request.META)
            ip=request.META.get('REMOTE_ADDR')
            import time
            ctime=time.time()
            # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问
            if ip not in self.VISIT_RECORD:
                self.VISIT_RECORD[ip]=[ctime,]
                return True
            self.history=self.VISIT_RECORD.get(ip)
            # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
            while self.history and ctime-self.history[-1]>60:
                self.history.pop()
            # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
            # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
            if len(self.history)<3:
                self.history.insert(0,ctime)
                return True
            else:
                return False
        def wait(self):
            import time
            ctime=time.time()
            return 60-(ctime-self.history[-1])
    频率组件

    视图函数引用组件

    from app01.auth import MyThro
    class Book(APIView):
        authentication_classes = [myAuthen,]    # 认证
        permission_classes = [myPermission,]    # 权限
        throttle_classes = [MyThro,]            # 频率
        def get(self,request):
            response = MyResponse()
            # print(request.user.name)    # 打印用户
            # print(request.auth.token)   # 携带的token
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    视图

     2)引用resful的方式

    创建频率组件

    from rest_framework.throttling import SimpleRateThrottle
    class MyThro(SimpleRateThrottle):
        scope = 'aaa'
        def get_cache_key(self, request, view):
            # return self.get_ident(request)        # 第一种写法
            return request.META.get('REMOTE_ADDR')  # 第二种写法

    视图函数

    from app01 import myserial
    from app01.auth import myPermission
    from app01.auth import MyThro
    class Book(APIView):
        authentication_classes = [myAuthen,]    # 认证
        permission_classes = [myPermission,]    # 权限
        throttle_classes = [MyThro,]            # 频率
        def get(self,request):
            response = MyResponse()
            # print(request.user.name)    # 打印用户
            # print(request.auth.token)   # 携带的token
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    视图

    2.1)如果是全局使用

    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES':[
            'rest_framework.parsers.JSONParser'     # 解析器
        ],
        "DEFAULT_AUTHENTICATION_CLASSES":["app01.auth.myAuthen",],     # 认证组件
        "DEFAULT_PERMISSION_CLASSES": ["app01.auth.myPermission", ],    # 权限组件
        "DEFAULT_THROTTLE_RATES":{
                'aaa':'1/m'      # 频率组件
        },
    }

    2.2)访问时间参数

    duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]   源码内容
    
    s ==> 秒
    m ==> 分
    h ==> 时
    d ==> 天

    2.3)小结

    -定义一个类:
    from rest_framework.throttling import SimpleRateThrottle
    class MyThro(SimpleRateThrottle):
        scope = 'aaa'
        def get_cache_key(self, request, view):
            # return self.get_ident(request)
            return request.META.get('REMOTE_ADDR')
        
    -setting中配置
    "DEFAULT_THROTTLE_RATES":{
        'aaa':'3/m'
    }
    
    -全局使用:
        'DEFAULT_THROTTLE_CLASSES':['app01.auth.MyThro',],
    -局部使用:
        throttle_classes=[MyThro,]

     二、rest-framework之分页

    1)简单分页:from rest_framework.pagination import PageNumberPagination 

    from app01 import myserial  # 序列化
    from app01.auth import myPermission     
    from app01.auth import MyThro
    from rest_framework.pagination import PageNumberPagination  # 分页
    class Book(APIView):
        authentication_classes = [myAuthen,]    # 认证
        permission_classes = [myPermission,]    # 权限
        throttle_classes = [MyThro,]            # 频率
        print('ok')
        def get(self,request):
            response = MyResponse()
            books=models.Book.objects.all()
    
            page = PageNumberPagination()
            page.page_size=2    # 定义默认显示每页显示的条数
            page.page_query_param='dasb'    # 定义页面的名字
            # 如 http://127.0.0.1:8000/books/?dasb=2&token=1d64b50ea99db6b66ab379dcfbfc5814  # dasb的第二页
            # page.page_query_param='dasb' # 不写默认是page
            page.page_size_query_param='max'    # 显示条数,可覆盖 page.page_size=2
            # 如http://127.0.0.1:8000/books/?dasb=2&max=3&token=1d64b50ea99db6b66ab379dcfbfc5814
            page.max_page_size=3    # 控制 page.page_size_query_param='max' 定义参数的最大值,超出了,也显示这里定义的3条数据
            page_book = page.paginate_queryset(books,request,view=self)
    
            ret = myserial.BookSer(instance=page_book,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    PageNumberPagination简单分页

     1.1)简单分页的4个参数

    # page_size=api_settings.PAGE_SIZE      # 每页大小,支持在settings.py里面配置
    # page_query_param='page'               # 查询每页的参数
    # page_size_query_param=None            # 指定每页的大小
    # page_size_query_param=None            # 每页最大显示多少

     2)偏移分页(没什么用)from rest_framework.pagination import LimitOffsetPagination

    from app01 import myserial  # 序列化
    from app01.auth import myPermission
    from app01.auth import MyThro
    from rest_framework.pagination import LimitOffsetPagination  # 偏移分页,从第一页开始
    class Book(APIView):
        authentication_classes = [myAuthen,]    # 认证
        permission_classes = [myPermission,]    # 权限
        throttle_classes = [MyThro,]            # 频率
        print('ok')
        def get(self,request):
            response = MyResponse()
            books=models.Book.objects.all()
    
            page = LimitOffsetPagination()
            page.default_limit = 2      # 默认显示2条
            page_book = page.paginate_queryset(books,request,view=self)
            # http://127.0.0.1:8000/books/?&token=1d64b50ea99db6b66ab379dcfbfc5814          # 默认显示2条
            # http://127.0.0.1:8000/books/?limit=3&token=1d64b50ea99db6b66ab379dcfbfc5814   # 根据limit设置的条数
    
            ret = myserial.BookSer(instance=page_book,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return JsonResponse(response.get_dic,safe=False)
    LimitOffsetPagination偏移分页

    2.1)偏移分页使用小结

    -from rest_framework.pagination import LimitOffsetPagination
    -生成一个对象
    -调用对象的.page.paginate_queryset(books, request, view=self)
    -会有返回结果:把结果序列化,返回
    -四个参数:
        默认大小
        default_limit = api_settings.PAGE_SIZE
        查询的条数
        limit_query_param = 'limit'
        偏移的条数
        offset_query_param = 'offset'
        最多多少条
        max_limit = None

     3)加密分页。from rest_framework.pagination import CursorPagination

    from app01 import myserial  # 序列化
    from app01.auth import myPermission
    from app01.auth import MyThro
    from rest_framework.pagination import CursorPagination  # 加密分页
    class Book(APIView):
        authentication_classes = [myAuthen,]    # 认证
        permission_classes = [myPermission,]    # 权限
        throttle_classes = [MyThro,]            # 频率
        def get(self,request):
            response = MyResponse()
            books=models.Book.objects.all()
    
            page = CursorPagination()
            page.ordering = 'nid'   # book表的nid,按照nid排序
            page.page_size = 2
            page_book = page.paginate_queryset(books,request,view=self)
            # http://127.0.0.1:8000/books/?token=1d64b50ea99db6b66ab379dcfbfc5814  默认第一页
            # http://127.0.0.1:8000/books/?cursor=cj0xJnA9NA%3D%3D&token=1d64b50ea99db6b66ab379dcfbfc5814   # ?cursor=随机字符串
            ret = myserial.BookSer(instance=page_book,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return page.get_paginated_response(ret.data)    # 包含返回上一页和下一页的随机字符串 cursor=随机字符串
    CursorPagination加密分页

    3.1)加密分页小结

    -from rest_framework.pagination import CursorPagination
    -生成一个对象
    -调用对象的.page.paginate_queryset(books, request, view=self)
    -会有返回结果:把结果序列化,返回
    -两个参数:
        按什么排序
        ordering = '-nid'
        page_size = 3

     

      三、rest-framework之的路由控制:目的返回好看的json界面

    1)使用实例归纳

    1、继承from rest_framework.response import Response
    2、视图函数中返回值:return Response(response.get_dic)
    3、settings.py中添加app。 'rest_framework'
    from rest_framework.renderers import HTMLFormRenderer,BrowsableAPIRenderer,JSONRenderer
    renderer_classes = [JSONRenderer,BrowsableAPIRenderer]

    2)举例,视图函数

    from app01 import myserial  # 序列化
    from app01.auth import myPermission
    from app01.auth import MyThro
    from rest_framework.pagination import CursorPagination  # 加密分页
    from rest_framework.renderers import BrowsableAPIRenderer,JSONRenderer
    
    from rest_framework.response import Response    # 可以返回一个很好看的页面
    class Book(APIView):
        authentication_classes = [myAuthen,]    # 认证
        permission_classes = [myPermission,]    # 权限
        renderer_classes = [BrowsableAPIRenderer,JSONRenderer]
        def get(self,request):
            response = MyResponse()
            books=models.Book.objects.all()
    
            page = CursorPagination()
            page.ordering = 'nid'   # book表的nid,按照nid排序
            page.page_size = 2
            page_book = page.paginate_queryset(books,request,view=self)
            ret = myserial.BookSer(instance=page_book,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return Response(response.get_dic)    # 返回页面,使用Response
    View Code

     

    注意:一定要使用页面访问测试该请求

     3)全局设置

    在settng中进行全局设置

    REST_FRAMEWORK = {
        'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer']
    }

     4)返回的页面是可以进行修改的

     4)路由控制。视图类继承的ViewSetMixin (as_view中必须传参数,字典形式)

    4.1)路由编写

    url(r'^books/', views.Book.as_view({'get':'get_all'})),

    4.2)视图函数编写

    注意:from rest_framework.viewsets import ViewSetMixin

    class Book(ViewSetMixin,APIView):     继承的ViewSetMixin 需要写在前面,才会这里面的as_view的方法

    from rest_framework.response import Response    # 可以返回一个很好看的页面
    from rest_framework.viewsets import ViewSetMixin
    class Book(ViewSetMixin,APIView):
        def get_all(self,request):
            response = MyResponse()
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return Response(response.get_dic)    # 返回页面,使用Response
    get_all

    5)路由传参格式

    5.1)路由编写

    url(r'^books.(?P<format>w+)/', views.Book.as_view()),

    5.2)视图函数

    from rest_framework.response import Response  
    class Book(APIView):
        def get(self,request,*args,**kwargs):
            response = MyResponse()
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return Response(response.get_dic)
    *args,**kwargs

    5.3)网页请求测试

    http://127.0.0.1:8000/books.json/?token=1d64b50ea99db6b66ab379dcfbfc5814

     5.6)路由总结

    url控制
    1) 原始的的url
        -url(r'^books/', views.Book.as_view()),
    2) 视图类继承的ViewSetMixin (as_view中必须传参数,字典形式)
        -url(r'^books/', views.Book.as_view('get':'get_all')),
    3) 全自动路由(自动生成路由)几乎不用
        from rest_framework import routers
        router = routers.DefaultRouter()
        # 2个参数,一个是匹配的路由,一个是视图中写的CBV的类
        router.register('book',views.Book)
        urlpatterns = [
            url(r'', include(router.urls)),
        ]

      原文链接:https://www.cnblogs.com/liuqingzheng/articles/9766413.html

    四、版本控制

    1)用get类进行控制:from rest_framework.versioning import QueryParameterVersioning

    settting中进行配置

    REST_FRAMEWORK = {
        ........
        'DEFAULT_VERSION': 'v1',            # 默认版本(从request对象里取不到,显示的默认值)
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }

    视图函数:

    from rest_framework.versioning import QueryParameterVersioning
    from rest_framework.response import Response
    class Book(APIView):
        versioning_class = QueryParameterVersioning
        def get(self,request,*args,**kwargs):
            response = MyResponse()
            print(request.version)
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return Response(response.get_dic)
    versioning_class = QueryParameterVersioning

    请求测试: http://127.0.0.1:8000/books/?version=v2&token=1d64b50ea99db6b66ab379dcfbfc5814

    2) 使用路由控制

    视图函数编写

    from rest_framework.versioning import URLPathVersioning
    from rest_framework.response import Response
    class Book(APIView):
        versioning_class = URLPathVersioning
        def get(self,request,*args,**kwargs):
            response = MyResponse()
            print(request.version)
            books=models.Book.objects.all()
            ret = myserial.BookSer(instance=books,many=True)
            response.msg = '查询成功'
            response.data=ret.data
            return Response(response.get_dic)
    versioning_class = URLPathVersioning

    路由控制

    url的2种写法都可以
    url(r'^(?P<version>[v1|v2]+)/books/', views.Book.as_view()),
    # url(r'^[v1|v2]+/books/', views.Book.as_view()),

    setting里面的配置可以注释掉,基于这种路由配置,setting里面就可以不用配置了

    请求测试: http://127.0.0.1:8000/v2/books/?token=1d64b50ea99db6b66ab379dcfbfc5814

    2.1) 路由编写的另一种格式

    url(r'^(?P<version>w+)/books/', views.Book.as_view()),

    需要在setting配置能访问的版本号

        'DEFAULT_VERSION': 'v1',            # 默认版本(从request对象里取不到,显示的默认值)
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version',          # URL中获取值的key

    3)视图总结

    # 第一种,默认的版本控制。(无用)
    #http://127.0.0.1:8000/books/?version=v1&token=1d64b50ea99db6b66ab379dcfbfc581
    # print(request.GET.get('version'))
    # print(request.query_params.get('version'))
    
    # 第二种,QueryParameterVersioning控制
    settings.py配置
    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',            # 默认版本(从request对象里取不到,显示的默认值)
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }
    视图函数导入
    from rest_framework.versioning import QueryParameterVersioning
    versioning_class = QueryParameterVersioning
    路由配置
    url(r'^books/', views.Book.as_view()),
    请求测试:http://127.0.0.1:8000/books/?version=v2&token=1d64b50ea99db6b66ab379dcfbfc5814
    
    # 第三种
    settings.py配置可以不用配置
    视图函数导入
    from rest_framework.versioning import URLPathVersioning
    versioning_class = URLPathVersioning
    url的2种写法都可以
    url(r'^(?P<version>[v1|v2]+)/books/', views.Book.as_view()),
    # url(r'^[v1|v2]+/books/', views.Book.as_view()),
    请求测试:http://127.0.0.1:8000/v2/books/?token=1d64b50ea99db6b66ab379dcfbfc5814
    3.1)url(r'^(?P<version>w+)/books/', views.Book.as_view()),
        添加settings的配置
        'DEFAULT_VERSION': 'v1',            # 默认版本(从request对象里取不到,显示的默认值)
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    View Code

     原文链接: https://www.cnblogs.com/liuqingzheng/articles/9766422.html

  • 相关阅读:
    OP_REQUIRES failed at conv_ops.cc:386 : Resource exhausted: OOM when allocating tensor with shape..
    Python中*args和**kwargs的区别
    命令行运行Python脚本时传入参数的三种方式
    关于 initWithNibName 和 loadNibNamed 的区别和联系-iPhone成长之路
    NSBundle介绍
    UIView总结
    iPhone How-to:如何调整UIView的Z-Order
    有关View的几个基础知识点-IOS开发
    NSNumber与NSInteger的区别
    iOS第三方开源库的吐槽和备忘
  • 原文地址:https://www.cnblogs.com/linu/p/10092399.html
Copyright © 2011-2022 走看看