一、访问频率补充
频率:
自定义:
1 定义一个类MyThrottles
allow_request(频率限制的逻辑) ==》这两个函数都是派生出来的,继承的类里面封装的。
wait(返回一个数字,给用户提示,还差多少秒)
2 局部使用:throttle_classes=[MyThrottles,]
3 全局使用:'DEFAULT_THROTTLE_CLASSES':['utils.common.MyThrottles',],
用内置的:(可以控制ip,和userid)
1 写一个类,继承SimpleRateThrottle
属性:scope = 'xxx' ===》scope是源码里的参数,必须要写
重写方法:get_cache_key
1 from rest_framework.throttling import SimpleRateThrottle 2 3 4 class VisitThrottle(SimpleRateThrottle): 5 # {IP:[]} 6 # {id:[]} 7 scope = 'xxx' # 这个必须要写 因为源码里有 8 9 def get_cache_key(self, request, view): # 重写get_cache_key方法 10 # ip=request.META.get('REMOTE_ADDR') 根据IP来限制访问频率 remote_addr如果是用的代理,获取的是代理IP,否则是主机的IP 11 # 用户一分钟只能访问5次 12 pk = request.user.pk # 根据用户的主键限制访问频率,默认是通过IP限制,可看源码 13 return pk
去setting里配置:'DEFAULT_THROTTLE_RATES':{
# 'xxx':'5/m', ===》这里的xxx是scope设定的值。
'xxx':'5/m',
}
2 局部使用:throttle_classes=[MyThrottles,]
3 全局使用:'DEFAULT_THROTTLE_CLASSES':['utils.common.MyThrottles',],
补充:
认证,想局部取消(禁用)===》只需要在认证的地方加上下面的:
authentication_classes=[]
同一个ip一分钟内只能访问三次 {ip1: [12:01:20,12:01:04,12:01:00],ip2: [],ip3: [],} #(1)取出访问者ip # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走 #现在是12:01:30 # (3)循环判断当前时间的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间, # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过 # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败
代码演示如下:
1 class MyThrottles(): 2 VISIT_RECORD = {} 3 def __init__(self): 4 self.history=None 5 def allow_request(self,request, view): 6 #(1)取出访问者ip 7 # print(request.META) 8 ip=request.META.get('REMOTE_ADDR') 9 import time 10 ctime=time.time() 11 # (2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问 12 if ip not in self.VISIT_RECORD: 13 self.VISIT_RECORD[ip]=[ctime,] 14 return True 15 self.history=self.VISIT_RECORD.get(ip) 16 # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间, 17 while self.history and ctime-self.history[-1]>60: 18 self.history.pop() 19 # (4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过 20 # (5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败 21 if len(self.history)<3: 22 self.history.insert(0,ctime) 23 return True 24 else: 25 return False 26 def wait(self): 27 import time 28 ctime=time.time() 29 return 60-(ctime-self.history[-1])
二、版本控制:
1 127.0.0.1/course/?version=v100000 ===》常用的两种版本书写方式,url带参数形式的
versioning_class = QueryParameterVersioning 只能写成这种形式的,因为源码里不是和处理以前列表形式一样来处理这个
用from rest_framework.versioning import QueryParameterVersioning
在视图类里:
versioning_class=QueryParameterVersioning(**不再是列表)
在setting里配置:
REST_FRAMEWORK={
'VERSION_PARAM':'version',
'DEFAULT_VERSION':'v2',
'ALLOWED_VERSIONS':['v1','v2']
}
视图类里:
request.version ===》 版本号
127.0.0.1/v1/course/ ===》这种形式比较常用
versioning_class = URLPathVersioning
用from rest_framework.versioning import URLPathVersioning
在视图类里:
versioning_class=URLPathVersioning**不再是列表)
在setting里配置:
REST_FRAMEWORK={
'VERSION_PARAM':'version',
'DEFAULT_VERSION':'v2',
'ALLOWED_VERSIONS':['v1','v2']
}
视图类里:
request.version
3 反向解析(了解)
urls
1 from django.conf.urls import url 2 from django.contrib import admin 3 from app01 import views 4 urlpatterns = [ 5 url(r'^admin/', admin.site.urls), 6 url(r'^testversion/', views.Test.as_view()), 7 url(r'^(?P<version>[v1|v2|v3]+)/testversion/', views.Test2.as_view(),name='ttt'), 8 url(r'^testres', views.Test3.as_view()), 9 url(r'^page', views.Page.as_view()), 10 ]
settings里相关配置
1 REST_FRAMEWORK={ 2 'VERSION_PARAM':'version', 3 'DEFAULT_VERSION':'v2', 4 'ALLOWED_VERSIONS':['v1','v2'] 5 }
views
1 from django.shortcuts import render, HttpResponse 2 3 # Create your views here. 4 from app01 import models 5 from rest_framework.views import APIView 6 from rest_framework.response import Response 7 8 from rest_framework.versioning import QueryParameterVersioning, URLPathVersioning 9 10 版本控制 11 class Test(APIView): 12 versioning_class = QueryParameterVersioning 13 14 def get(self, request, *args, **kwargs): 15 print(request.version) 16 17 return Response('ok') 18 19 20 from django.urls import reverse 21 22 反向解析 仅作了解 用的比较少 23 class Test2(APIView): 24 versioning_class = URLPathVersioning 25 26 def get(self, request, *args, **kwargs): 27 print(request.version) 28 url = request.versioning_scheme.reverse(viewname='ttt', request=request) 29 print(url) 30 url2 = reverse(viewname='ttt', kwargs={'version': 'v1'}) 31 print(url2) 32 33 return Response('ok ttest2')
三、响应器:
以后项目中用:(返回的格式,只是json格式)
REST_FRAMEWORK={
'DEFAULT_RENDERER_CLASSES':['rest_framework.renderers.JSONRenderer',],
}
补充一点:
查找模板的时候:先从自己app里找,找不到去项目,再找不到,去各个app里找
views
1 from rest_framework.renderers import BrowsableAPIRenderer, JSONRenderer, AdminRenderer 2 3 4 class Test3(APIView): 5 renderer_classes=[BrowsableAPIRenderer] 6 def get(self, request, *args, **kwargs): 7 return Response({ 8 'name': 'qlz', 9 'age': 18, 10 'name1': 'qlz', 11 'age2': 18, 12 })
settings
REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ['rest_framework.renderers.JSONRenderer'], }
四、分页
1 简单分页
127.0.0.1/course/page=3
PageNumberPagination
#每页显示多少条api_settings.PAGE_SIZE
#page_size =
#查询指定页码的重命名
#page_query_param = 'page'
#指定每页显示条数
#page_size_query_param = None
#限制每页显示最大条数
#max_page_size = None
2 偏移分页
127.0.0.1/course/offset=10&limit=5
LimitOffsetPagination
# default_limit:默认显示多少条
# max_limit:最大显示多少条
# limit_query_param:重新命名limit(limit=4:表明显示四条,受max_limit的限制)
# offset_query_param:指定查询的标杆名(offset=1:表明从第二条开始,往后偏移)
3 加密分页
后台返回的url:127.0.0.1/course/page=dfgeg
CursorPagination
cursor_query_param = 'cursor':查询的名字
page_size = api_settings.PAGE_SIZE:每页显示的条数
ordering = '-created' :按谁排序
补充:(1)修改数据属性的方式:
1 再setting里配置每页条数
2 写一个类,继承它,属性重写
3 再对象里修改
(2)my_page.get_paginated_response(ser.data)
# 对Response做了封装,返回内容里有总条数,上一页,下一页的链接
views
1 from rest_framework.serializers import ModelSerializer 2 from rest_framework import serializers 3 4 5 class BookSer(serializers.ModelSerializer): 6 class Meta: 7 model = models.Book 8 fields = '__all__' 9 10 11 from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination 12 13 14 # class Page(APIView): 15 # def get(self,request,*args,**kwargs): 16 # ret=models.Book.objects.all() 17 # my_page=PageNumberPagination() 18 # my_page.page_size=2 19 # my_page.page_size_query_param='size' 20 # my_page.max_page_size=5 21 # 22 # page_list=my_page.paginate_queryset(ret,request,self) 23 # ser=BookSer(instance=page_list,many=True) 24 # # 1 再setting里配置每页条数 25 # # 2 写一个类,继承它,属性重写 26 # # 3 再对象里修改 27 # ''' 28 # 每页显示多少条api_settings.PAGE_SIZE 29 # page_size = 30 # 查询指定页码的参数 31 # page_query_param = 'page' 32 # 指定每页显示条数 33 # page_size_query_param = None 34 # 限制每页显示最大条数 35 # max_page_size = None 36 # ''' 37 # 38 # return Response(ser.data) 39 40 # class Page(APIView): 41 # def get(self,request,*args,**kwargs): 42 # ret=models.Book.objects.all() 43 # my_page=LimitOffsetPagination() 44 # my_page.default_limit=3 45 # my_page.max_limit=5 46 # 47 # 48 # page_list=my_page.paginate_queryset(ret,request,self) 49 # ser=BookSer(instance=page_list,many=True) 50 # # 1 再setting里配置每页条数 51 # # 2 写一个类,继承它,属性重写 52 # # 3 再对象里修改 53 # ''' 54 # default_limit:默认显示多少条 55 # max_limit:最大显示多少条 56 # limit_query_param:重新命名limit(limit=4:表明显示四条,受max_limit的限制) 57 # offset_query_param:指定查询的标杆名(offset=1:表明从第二条开始,往后偏移) 58 # ''' 59 # 60 # # return Response(ser.data) 61 # # 对Response做了封装,返回内容里有总条数,上一页,下一页的链接 62 # return my_page.get_paginated_response(ser.data) 63 64 65 class Page(APIView): 66 def get(self, request, *args, **kwargs): 67 ret = models.Book.objects.all() 68 my_page = CursorPagination() 69 my_page.ordering = 'id' 70 my_page.page_size = 2 71 page_list = my_page.paginate_queryset(ret, request, self) 72 ser = BookSer(instance=page_list, many=True) 73 # 1 再setting里配置每页条数 74 # 2 写一个类,继承它,属性重写 75 # 3 再对象里修改 76 ''' 77 cursor_query_param = 'cursor':查询的名字 78 page_size = api_settings.PAGE_SIZE:每页显示的条数 79 ordering = '-created' :按谁排序 80 ''' 81 82 # return Response(ser.data) 83 # 对Response做了封装,返回内容里有总条数,上一页,下一页的链接 84 return my_page.get_paginated_response(ser.data) 85 # return Response(ser.data)
自己封装response对象
。。。。
作业:
1 前端操作cookie
2 频率显示中文(去源码里找,替换)
3 版本控制,不在setting里配置,实现
5 redis安装上(windows/linux)
4 axios
5 cc视频 ==》路飞学城用的视频代理,现在一般不自己搞代理,浪费人力物力,买的代理划算。