自定义频率类
from rest_framework.throttling import BaseThrottle
import time
class MyThrottling(BaseThrottle):
# 存放用户访问记录:{IP1:[时间2,时间1]}
user_record = {}
def __init__(self):
self.history = None
def allow_request(self, request, view):
# 取出访问者的IP
ip = request.META.get('REMOTE_ADDR')
# 取出当前时间
ctime = time.time()
# 判断当前ip不在访问字典里
if ip not in self.user_record:
# 将ip添加进去,并且直接返回True,表示第一次访问
self.user_record[ip] = [ctime]
return True
# 当前访问者的时间列表[时间2,时间1]
self.history = self.user_record.get(ip)
# 循环判断当前ip的列表是否有值,并且当前时间减去列表的最后一个时间大于60s
while self.history and ctime - self.history[-1] > 60:
# 将超过60秒的访问时间取出
self.history.pop()
# 判断是否访问超过3次
if len(self.history) < 3:
# 将当前时间插入到列表第一个位置,并返回True
self.history.insert(0, ctime)
return True
return False
def wait(self):
ctime = time.time()
return 60 - (ctime - self.history[-1])
频率功能源码分析
-源码里执行的频率类的allow_request,在SimpleRateThrottle中找allow_request
-116行
if self.rate is None:
1.到self.rate中
def __init__(self):
# 从频率类反射'rate',没有就返回None,就会执行下面的代码
if not getattr(self, 'rate', None):
# 返回了'3/m'
self.rate = self.get_rate()
# 返回给um_requests=3,duration=60
self.num_requests, self.duration = self.parse_rate(self.rate)
-到self.get_rate()中
# 如果频率类中没有scope属性就抛异常
if not getattr(self, 'scope', None):
msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
self.__class__.__name__)
raise ImproperlyConfigured(msg)
try:
# 有scope属性就返回下面的字典取值,就是配置文件中配置的字典
# {'ss': '3/m',}---根据ss取到了 '3/m'
return self.THROTTLE_RATES[self.scope]
-到self.parse_rate中
def parse_rate(self, rate):
if rate is None:
return (None, None)
# 将rate(3/m)根据'/'切分解压赋值给num(3), period(m)
num, period = rate.split('/')
# 将字符串3转换为整型3
num_requests = int(num)
# {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[m]
# duration = 60
duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
# 返回num_requests(3), duration(60)
return (num_requests, duration)
def allow_request(self, request, view):
if self.rate is None:
return True
# 我们写的get_cache_key,返回什么就以什么做限制
self.key = self.get_cache_key(request, view)
if self.key is None:
return True
# self.history是从缓存中获取的访问者的时间列表,如果获取不到就是空,如果拿到了就是访问者的数据列表[时间2,时间1]
self.history = self.cache.get(self.key, [])
# self.now是当前时间
self.now = self.timer()
# 循环判断当前ip的列表是否有值,并且当前时间减去列表的最后一个时间大于规定时间
while self.history and self.history[-1] <= self.now - self.duration:
# 将超过时间的访问时间取出
self.history.pop()
# 判断是否访问超过规定次数
if len(self.history) >= self.num_requests:
# 超过规定次数返回True
return self.throttle_failure()
# 没超过规定次数返回True
return self.throttle_success()
'写频率类只需要继承SimpleRateThrottle,重写get_cache_key方法,配置属性scope,在配置文件中配置即可'
分页功能
'查询所有的接口才需要分页'
1.分页后端写法是固定的,前端展示形式是不一样的
-PC端的分页是下一页点击
-app中的分页是下拉加载更多
2.drf中分页的使用
-写一个继承了drf的三个分页类之一的类
-重写某几个类属性
-把它配置在继承自GenericAPIView+ListModelMixin的子视图上
3.分页类
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
-PageNumberPagination
class YouPageNumberPagination(PageNumberPagination):
# 重写四个类属性
page_size = 2 # 每页显示的条数
page_query_param = 'page' # /?page=2 查询第几页的参数
page_size_query_param = 'size' # /?page=2&size=4 查询第2页,每页显示4条
max_page_size = 5 # 限制size每页最多条
-LimitOffsetPagination
class YouPageNumberPagination(LimitOffsetPagination):
# 重写四个类属性
default_limit = 2 # 每页显示的条数
limit_query_param = 'limit' # /?limit=2 这页显示2条
offset_query_param = 'offset' # /?limit=2&offset=4 从第4条开始,取2条数据
max_limit = 5 # 限制size每页最多条
-CursorPagination
class YouPageNumberPagination(CursorPagination):
# 重写三个类属性
# 这个只能上一页和下一页,但它的分页效率是最高的
cursor_query_param = 'cursor'
page_size = 2 # 每页显示的条数
ordering = 'id' # 按什么排序,必须是表中字段
4.局部使用
pagination_class = YouPageNumberPagination # 必须继承GenericAPIView才有这个属性
5.如果是继承APIView,需要自己写
class BookView1(APIView):
def get(self, request):
qs = Book.objects.all()
page = MyPageNumberPagination()
res = page.paginate_queryset(qs, request)
ser = BookSerializer(instance=res,many=True)
return Response(ser.data)
排序功能
'查询所有才设计到排序,其他接口都不需要'
-必须是继承GenericAPIView+ListModelMixin的子视图类上
1.排序类使用
from rest_framework.filters import OrderingFilter
class BookView(ModelViewSet):
# 排序类的配置
filter_backends = [OrderingFilter]
# 按指定字段排序
ordering_fields = ['price', 'id']
serializer_class = BookSerializer
queryset = Book.objects.all()
2.支持前端的访问形式
'先按price的降序排,在按id的升序排'
http://127.0.0.1:8000/books/?ordering=-price,id
3.如果是继承APIView,需要自己写,需要从请求地址中取出排序规则,自己排序
'price','-id'=reqeust.query_params.get('ordering').split(',')
qs = Book.objects.all().order_by('price','-id')
'分页好排序能一起使用,但是是先排序后分页'
4.分页和排序能一起用,但是是先排序后分页的
'先按price的降序排,在按id的升序排,查询第2页,每页显示2条'
http://127.0.0.1:8000/books/?page=2&size=2&ordering=-price,id
过滤功能
'查询所有才设计到过滤,其他接口都不需要'
1.过滤是restful规范中的一条,请求地址中带的过滤条件(分页、排序、过滤)统称为过滤
2.过滤类使用
from rest_framework.filters import SearchFilter
class BookView(ModelViewSet):
# 过滤类的配置
filter_backends = [SearchFilter]
# 指定过滤指定
search_fields = ['name', 'publish']
serializer_class = BookSerializer
queryset = Book.objects.all()
3.支持前端的访问形式
'只要name中或publish中有红都搜出来'
http://127.0.0.1:8000/books/?search=红
'内置过滤类只能通过search写条件,如果配置了多个字段,是or的条件'
作业
1 自定义频率类,写一遍
2 使用3种分页方式,实现对查询所有数据接口的分页
3 带排序,带按名字过滤
#----部分人写----
4 继承APIView,实现分页,返回格式跟之前一样
class BookView1(APIView):
def get(self, request):
qs = Book.objects.all()
page = MyPageNumberPagination()
res = page.paginate_queryset(qs, request)
ser = BookSerializer(instance=res,many=True)
return Response(ser.data)
2
-PageNumberPagination
class YouPageNumberPagination(PageNumberPagination):
# 重写四个类属性
page_size = 2 # 每页显示的条数
page_query_param = 'page' # /?page=2 查询第几页的参数
page_size_query_param = 'size' # /?page=2&size=4 查询第2页,每页显示4条
max_page_size = 5 # 限制size每页最多条
-LimitOffsetPagination
class YouPageNumberPagination(LimitOffsetPagination):
# 重写四个类属性
default_limit = 2 # 每页显示的条数
limit_query_param = 'limit' # /?limit=2 这页显示2条
offset_query_param = 'offset' # /?limit=2&offset=4 从第4条开始,取2条数据
max_limit = 5 # 限制size每页最多条
-CursorPagination
class YouPageNumberPagination(CursorPagination):
# 重写三个类属性
# 这个只能上一页和下一页,但它的分页效率是最高的
cursor_query_param = 'cursor'
page_size = 2 # 每页显示的条数
ordering = 'id' # 按什么排序,必须是表中字段
3
1.类的使用
from rest_framework.filters import OrderingFilter, SearchFilter
class BookView(ModelViewSet):
filter_backends = [OrderingFilter, SearchFilter]
# 按指定字段排序
ordering_fields = ['price', 'id']
# 指定过滤指定
search_fields = ['name']
serializer_class = BookSerializer
queryset = Book.objects.all()
2.支持前端访问形式
'获取name字段中有"西"的数据,在按price的降序排,最后按id的升序排'
http://127.0.0.1:8000/books/?ordering=-price,id&search=西
标签:分页,自定义,self,class,rate,过滤,排序,page,size
From: https://www.cnblogs.com/riuqi/p/16777726.html