首页 > 其他分享 >自定义频率类与分页、排序、过滤功能

自定义频率类与分页、排序、过滤功能

时间:2022-10-10 22:57:41浏览次数:56  
标签:分页 自定义 self class rate 过滤 排序 page size

自定义频率类

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

相关文章