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

原文地址:https://www.cnblogs.com/linu/p/10092399.html