DRF-(7)

内容概览

  • 自定义频率类
  • 频率源码分析
  • 分页、排序、过滤

自定义频率类

class Throttle_app01(BaseThrottle):
    scope = 'scope'
    VISIT_RECORD = {}  # 存放用户访问记录:{判断依据:[访问时间1,访问时间2]}

    def __init__(self):
        self.history = None  # 保存时间列表

    def allow_request(self, request, view):
        ip = request.META.get('REMOTE_ADDR')
        import time
        ctime = time.time()  # 获取当前时间
        if ip not in self.VISIT_RECORD:  # 判断当前用户ip是否在访问字典中
            self.VISIT_RECORD[ip] = [ctime]  # 如果不存在说明当前ip是第一次访问,在访问字典中新建一条数据并返回True
            return True
        self.history = self.VISIT_RECORD.get(ip)  # 如果当前用户ip访问过,获取当前ip的访问时间列表
        while self.history and ctime - self.history[-1] > 60:
            self.history.pop()  # 如果列表中有值且最早登录时间大于限定时间,则删除该时间
        if len(self.history) < 3:
            self.history.insert(0, ctime)
            return True  # 如果时间列表中个数小于限定次数,则将当前时间插入到第一条,并返回True
        else:
            return False  # 如果时间列表中个数大于限定次数,则不通过验证返回False

    def wait(self):
        ctime = time.time()
        return 60 - (ctime-self.history[-1])  # 返回最早登录时间与限定时间之间相差多少时间

频率源码分析

# SimpleRateThrottle
	-源码里执行的频率类的allow_request,读SimpleRateThrottle的allow_request
    
class SimpleRateThrottle(BaseThrottle):
    cache = default_cache
    timer = time.time
    cache_format = 'throttle_%(scope)s_%(ident)s'
    scope = None
    THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
    def __init__(self):  # 只要类实例化得到对象就会执行
        if not getattr(self, 'rate', None): # 去频率类中反射rate属性或方法,发现没有,返回了None,这个if判断就符合,执行下面的代码
            self.rate = self.get_rate()  #执行get_rete方法,返回了  '3/m'
        self.num_requests, self.duration = self.parse_rate(self.rate)  # 执行parse_rate方法,传入字典中填入的3/m;返回结果是一个元组

    def get_rate(self):
         return self.THROTTLE_RATES[self.scope] # 字典取值,配置文件中咱们配置的字典{'ss': '3/m',},根据ss取到了 '3/m'

    def parse_rate(self, rate):
        if rate is None:
            return (None, None)
        num, period = rate.split('/')  # 根据/切割并解压赋值
		# num = '3', period = 'm'
        num_requests = int(num)  # 将字符串'3'转换为整型
        duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]  # 先通过字符串索引取值,取到'm';在通过字典的按key取值,取到60
        return (num_requests, duration)

    def allow_request(self, request, view):
        if self.rate is None:  # 经过__init__可以获取到self.rate的值,如果为None则不校验直接通过
            return True
    
        self.key = self.get_cache_key(request, view)   # 咱们自己写的,返回什么就以什么做限制  咱们返回的是ip地址
        if self.key is None:  # self.key=当前访问者的ip地址
            return True
     
        self.history = self.cache.get(self.key, [])   # self.history 访问者的时间列表,从缓存中拿到,如果拿不到就是空列表,如果之前有 [时间2,时间1]
     
        self.now = self.timer()  # 当前时间
        while self.history and self.history[-1] <= self.now - self.duration:  # 判断记录中最早时间是否早于当前时间减去限定时间,将超出这个时间的记录删除
            self.history.pop()
        if len(self.history) >= self.num_requests:  # 将记录中的个数与指定个数做判断
            return self.throttle_failure()  # 方法返回值为False
        return self.throttle_success()  # 方法返回值为True
    
    
  # 总结:以后要再写频率类,只需要继承SimpleRateThrottle,重写get_cache_key,配置类属性scope,配置文件中配置一下就可以了

分页、排序、过滤

分页功能

只有查询所有数据的接口才需要使用到分页
分页后端写法是固定的,前端展示形式不一样

from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination
# 继承这三个类都可以使用分类


class BookPageNumber(PageNumberPagination):
    page_size = 5  # 每页默认显示5条数据
    page_query_param = 'page'  # 页数在路由中过滤条件的名字:/books/?page=3  第三页
    page_size_query_param = 'size'  # 在路由过滤条件中写入  /books/?size=10  则表示每页展示10条数据
    max_page_size = 20  # 表示每页最多展示20条数据


class BookLimitOffset(LimitOffsetPagination):
    default_limit = 5  # 默认每页展示数据数量
    limit_query_param = 'limit'  # /book/?limit=6  表示展示6条数据
    offset_query_param = 'offset'  # /book/?limit=2&offset=10  表示从第10条开始往后展示2条数据
    max_limit = 10  # 表示最多展示10条数据


class BookCursor(CursorPagination):
    cursor_query_param = 'cursor'  # 路由过滤条件名
    page_size = 5  # 每页展示条数
    ordering = 'id'  # 按照什么排序,必须为表中字段;-id表示降序排序
    """这个类只能够上一页和下一页,不能够直接跳转到指定页数;适用于数量庞大的数据展示"""

"""把它配置到继承了GenericAPIView+ListModelMixin的子视图类属性上"""
class BookView(ModelViewSet):
    pagination_class = paginations.BookCursor
排序

查询所有数据的接口才需要使用到排序
继承了GenericAPIView和ListModelMixin的子视图类才能配置

from rest_framework.filters import OrderingFilter

class BookView(ModelViewSet):
    filter_backends = [OrderingFilter, ]  # 配置排序类
    ordering_fields = ['id', 'price']  # 配置排序的字段

"""http://127.0.0.1:8000/books/?ordering=price,id   路由写法,先通过价格排序,价格相同通过id排序,默认为升序排序,加-号表示降序排序"""
过滤

过滤也只有在查询所有接口才需要使用
继承了GenericAPIView和ListModelMixin的子视图类才能配置

from rest_framework.filters import SearchFilter

class BookView(ModelViewSet):
    filter_backends = [SearchFilter, ]  # 配置过滤类
    search_fields = ['name', 'publish']  # 配置过滤的字段
    """http://127.0.0.1:8000/books/?search=三  只要name中或publish中有三都能搜出来
内置过滤类只能通过search写条件"""

练习

"""1 自定义频率类,写一遍"""
class Throttle_app01(BaseThrottle):
    scope = 'scope'
    VISIT_RECORD = {}  

    def __init__(self):
        self.history = None

    def allow_request(self, request, view):
        ip = request.META.get('REMOTE_ADDR')
        import time
        ctime = time.time()  
        if ip not in self.VISIT_RECORD:  
            self.VISIT_RECORD[ip] = [ctime] 
            return True
        self.history = self.VISIT_RECORD.get(ip)
        while self.history and ctime - self.history[-1] > 60:
            self.history.pop()  
        if len(self.history) < 3:
            self.history.insert(0, ctime)
            return True  
        else:
            return False  

    def wait(self):
        ctime = time.time()
        return 60 - (ctime-self.history[-1]) 

"""2 使用3种分页方式,实现对查询所有数据接口的分页"""
from rest_framework.pagination import PageNumberPagination, LimitOffsetPagination, CursorPagination


class BookPageNumber(PageNumberPagination):
    page_size = 5
    page_query_param = 'page'
    page_size_query_param = 'size'
    max_page_size = 10


class BookLimitOffset(LimitOffsetPagination):
    default_limit = 5
    limit_query_param = 'limit'
    offset_query_param = 'offset'
    max_limit = 10

class BookCursor(CursorPagination):
    cursor_query_param = 'cursor'
    page_size = 5
    ordering = 'id'

"""3 带排序,带按名字过滤"""
class BookView(ModelViewSet):
    queryset = models.Book.objects.all()
    serializer_class = serializers.BookModelSerializer
    filter_backends = [OrderingFilter, SearchFilter]
    ordering_fields = ['id', 'price']
    search_fields = ['name']


class PublishView(ModelViewSet):
    queryset = models.Publish.objects.all()
    serializer_class = serializers.PublishModelSerializer
    filter_backends = [OrderingFilter, SearchFilter]
    ordering_fields = ['id', 'city']
    search_fields = ['name']

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值