权限、认证、频率、过滤、排序、分页、全局异常源码分析

权限源码

 

 if not permission.has_permission(request, self)  这里的self并不是指对象,指的是视图类的对象(view),视图类中的has_permission中有三个参数(self,request,view)

 配置在视图类上一个个权限类的对象列表 [权限对象1,权限对象2]

 认证源码

 所以要从根上找

 从request中找,去Request类中找user---》方法包装成了数据属性

 因为认证类抛异常继承的是APIException,所以将只要符合APIException全部捕获。

 self就是request对象,后续 request.user就是认证类返回的第一个参数

 认证类可以配置多个,但是如果有一个返回了,后续的就不走了

self.authenticators 是request对象的属性,是在Request实例化的时候传入的,它什么时候实例化的,包装新的Reqeust时传入的---》APIView的dispatch--》

 

频率源码分析

throttle_durations.append(throttle.wait()) 这句是显示还剩多长时间访问

 频率类要写:

  1、写一个类,继承BaseThrottle

  2、在类中重写:allow_request方法,传入三个参数

  3、在allow_request写限制逻辑,如果能访问,返回 True

  4、如果超了次数,就不能访问,返回False

  5、局部配置在视图类上

  6、全局配置在配置文件中

我们在drf中写的时候,不需要继承BaseThrottle,继承了SimpleRateThrottle,重写get_cache_key

例子:

  自定义频率类,实现一分钟只能访问三次的控制

(1)取出访问者ip
(2)判断当前ip不在访问字典里,添加进去,并且直接返回True,表示第一次访问,在字典里,继续往下走
(3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
(4)判断,当列表小于3,说明一分钟以内访问不足三次,把当前时间插入到列表第一个位置,返回True,顺利通过
(5)当大于等于3,说明一分钟内访问超过三次,返回False验证失败

SimpleRateThrottle 源码分析

self.now = self.timer(),就是在使用时给time.time加上(),进行调用

补第一张图的文字说明

自定义频率类

逻辑思路和源码一致

from rest_framework.throttling import BaseThrottle


class MyThrottle(BaseThrottle):
    # VISIT_RECORD = {'192.168.1.1':[当前时间,当前时间,访问时间列表]}
    VISIT_RECORD = {}  #空字典

    def __init__(self):
        self.history = []

    def allow_request(self, request, view):
        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, ]  # VISIT_RECORD = {'192.168.1.1':[当前时间2,当前时间1,]}
            return True
        # (3)循环判断当前ip的列表,有值,并且当前时间减去列表的最后一个时间大于60s,把这种数据pop掉,这样列表中只有60s以内的访问时间,
        self.history = self.VISIT_RECORD[ip]  # 访问时间列表
        while self.history and ctime - self.history[-1] > 60:  # 循环删除1分钟之前访问的实际
            self.history.pop()

        # 最后self.history都剩下是一分钟之内的时间了
        # (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])

 

过滤源码分析

ListModelMixin---》list方法

 

 取出一个个配置在视图类上的过滤类,依次实例化得到对象后执行对象的filter_queryset方法完成过滤---》最终返回的数据,就是过滤后的数据

排序源码分析

针对于查询所有接口---》继承:GenericAPIView+ListModelMixin---》只需要在视图类中写一个类属性---》filter_backends = [排序类]

 

分页源码分析

GenericAPIView+ListModelMixin

class  Pager(APIView):
    def get(self,request,*args,**kwargs):
        # 获取所有数据
        ret=models.Book.objects.all()
        # 创建分页对象
        page=PageNumberPagination()
        # 在数据库中获取分页的数据
        page_list=page.paginate_queryset(ret,request,view=self)
        # 对分页进行序列化
        ser=BookSerializer1(instance=page_list,many=True)
        # return Response(ser.data)
        # 这个也是返回Response对象,但是比基本的多了上一页,下一页,和总数据条数(了解即可)
        return page.get_paginated_response(ser.data)
        return Response(ser.data) # 只会有数据,不会有上一页和下一页,总条数

 

全局异常处理

 exception_handler就是配置文件中配置的一个函数-->默认的

 

默认执行的是:

rest_framework.views.exception_handler函数---》只处理了drf的异常

1、写一个函数在内部处理

 from rest_framework.views import exception_handler
    def common_exception_handler(exc,context):
        res=exception_handler(exc,context)
        if res: #这次异常是drf的,并且它处理了
            # 我们要统一返回格式
            return Response({'code':888,'msg':"系统异常(drf异常),请联系系统管理员:%s"%res.data.get('detail',None)})
        else:
            return Response({'code': 999, 'msg': "系统异常(非drf异常),请联系系统管理员:%s" % str(exc)})

2、配置在配置文件上

 

posted @ 2023-09-13 20:11  别管鱼油我了  阅读(5)  评论(0编辑  收藏  举报