DRF从入门到精通七(频率源码分析)

2024-01-02 20:46:26

一、频率源码分析

从最开始的DRF知识介绍到现在,我们也知道频率组件是在APIView类源码中的dispatch方法里面执行了三大认证,这三大认证也是在视图类方法之前就执行了。

APIView的频率源码分析

		'这里我就不一个个罗列出来了,就直接写有关频率源码了。'
    	def dispatch(self, request, *args, **kwargs):
		    try:
		    	'执行三大认证'
            	self.initial(request, *args, **kwargs)
        
        'APIView里面的initial方法'  	
	    def initial(self, request, *args, **kwargs):
	    	'执行频率'
        	self.check_throttles(request)

		'APIView里面的check_throttles方法'
		def check_throttles(self, request):
	        throttle_durations = []
	        '这里的self.get_throttles方法,就是获取视图类中一个个的频率类的对象,它是一个列表'
	        '然后循环遍历,把一个个的频率类的对象给了throttle'
	        for throttle in self.get_throttles():
	        	'这里就是为什么我们继承BaseThrottle需要重写这个方法的原因。'
	            if not throttle.allow_request(request, self):
		            '''
		            当这个方法的返回值为False时,则获取等待时间并添加到throttle_durations这个列表中
		            这里的throttle.wait就是重写的wait方法的返回值,返回的还剩多长时间才能进行下一次的访问
		            '''
	                throttle_durations.append(throttle.wait()) 
			
			'如果执行了频率限制,就会执行这里'
	        if throttle_durations:
	        	'这里的列表表达式就是duration在这个throttle_durations列表中有还剩多长时间的数据'
	            durations = [
	                duration for duration in throttle_durations
	                if duration is not None  # 这里它过滤掉了为空的
	            ]
				
				'然后在这里取出了这个列表中的最大值,例子:duration[33,54]'
	            duration = max(durations, default=None) # 这里就会取出最大的那个54
	            '这里的self就是视图类的对象,所以我们在APIView中找到了throttled方法'
	            self.throttled(request, duration)
	            'duration有两种情况,一种是有值(被限制频率),一种是None(没有被限制频率)'
        
        
        'APIView中的throttled方法'
        '我们可以看到在上面它把最后的duration传入到这个throttled方法中了'
        def throttled(self, request, wait):
        	'所以这里的wait就是最后的druation的值,所以这里的wait也是有两种情况,有值或者None'
	        raise exceptions.Throttled(wait)
	        '''
	        这里的exceptions.Throttled()就是from rest_framework.exceptions import Throttled
	        也就是类实例化得到对象后把wait也就是duration里面的数字或者None传入进去,
	        具体这个exceptions.Throttled方法里面是如果把我们限制的数字拼接到页面上的这里就不多介绍
	        '''

SimpleRateThrottle 频率类源码分析

我们从上面APIView中的频率源码知道,继承SimpleRateThrottle频率类和继承BaseThrottle频率类,本质都是差不多,都是重写一些方法,而SimpleRateThrottle频率类,它的源码中就是继承了BaseThrottle频率类,所以这里我就直接看SimpleRateThrottle 的源码

'我们自己写自定义频率类的时候,继承SimpleRateThrottle频率类,发现并没有重写allow_request方法,而是写的别的'
	'''
	所以我们在这里去SimpleRateThrottle源码中看看它是如何实现的,
	在SimpleRateThrottle源码中我们看到了它重写了allow_request方法,并且它就是继承了BaseThrottle类
	'''
class SimpleRateThrottle(BaseThrottle):
    def allow_request(self, request, view):
		 """
	    参数:
	    - request: 当前的请求对象
	    - view: 请求对应的视图对象或处理函数
	
	    返回:
	    - True: 允许请求通过
	    - False: 请求被限制
	
	    注意: 这里的逻辑假设限流器的主要参数在初始化时已经设置,
	    如速率(rate)、缓存键(key)、历史记录(history)等。
    	"""
    
      	'我们自己自定义的时候写了这个rate,例如:rate=5/m'
        if self.rate is None: # 当rate为空执行,直接没有限制
            return True
		
		'这里调用了get_chche_key(),这就是为什么我们自定义频率类重写的是这个方法'
		'所以这里的self.key就是重写的get_chche_key方法的返回值,例如按照ip限制,那就是ip'
        self.key = self.get_cache_key(request, view)

		'这里self.key也就是get_chche_key方法的返回值是空的时候执行,相当于没有进行限制'
        if self.key is None:
            return True
		
		'''
		self.key就是get_chche_key方法的返回的限制
		self.cache.get就是缓存,默认设置缓存在内存中,然后去缓存中根据self.key的值,去取出访问者时间列表
		如果没有则是[]
		self.history就是当前ip,访问的时间列表
		'''
        self.history = self.cache.get(self.key, [])

		'这里的self.timer就是加括号调用time.time实例化对象self.now,拿到当前执行时间'
        self.now = self.timer()  # timer = time.time没有加括号
		
		'''
		这里就是拿到访问列表的最后一个时间数据(也是最早的时间数据,这个我们继承BaseThrottle写自定义频率类的时候做过这个类似的逻辑)
		然后当它小于或者等于,当前时间减去self.duration也就是对应的60秒,当它超过了60秒就给超出的数据弹出
		'''
        while self.history and self.history[-1] <= self.now - self.duration:
            self.history.pop()
        
        '''
        这里跟我们继承BaseThrottle写自定义频率类时类似,就是判断这个列表中的时间数据有几个,
        当它大于我们我们设置的rate=5/m中的5个就执行
        '''
        if len(self.history) >= self.num_requests:
        	'这里的self.throttle_failure方法也是SimpleRateThrottle源码内的方法,它直接返回了False'
            return self.throttle_failure()
            '这里我们就可以知道,可以在自定义频率类中重写这个self.throttle_failure方法,定制返回的文字'

		'''
		这个selfthrottle_success方法跟上面一样,它直接返回True,
		def throttle_success(self):
		它把没有被限制的时间一个个放到history这个列表的第零个位置,这也就是我上面说的history[-1]是最早的时间
	        self.history.insert(0, self.now)
	        然后在这里又放入到缓存当中
	        self.cache.set(self.key, self.history, self.duration)
	        return True
		'''
        return self.throttle_success()


	'在上面我并没有去说self.duration和self.num_requests到底为什么是rate=5/m中的60和5。我在这里说一下'
	'首先直接按住Ctrl加鼠标左键点击self.duration就跳转到了它的初始化方法了'
	def __init__(self):
		'这里可以看到self.duration和self.num_requests是self.parse_rate解压赋值的,所以我们去看看这个方法'
	    self.num_requests, self.duration = self.parse_rate(self.rate)
	
	'这个parse_rate也是SimpleRateThrottle的方法'
	def parse_rate(self, rate):
        '当rate为空时,设置两个空'
        if rate is None:  
            return (None, None)
        
        '当有值时按/进行切分,然后解压赋值给num、period两'
        num, period = rate.split('/') # 例子5/m  所以这里的num就是5,period就是m
        '然后再把/斜杠前的数据强转成数字类型后赋值给num-requests'
        num_requests = int(num) # 到了这一步我们就知道,为什么num_requests就是rate=5/m的5了
        
        '''
        这里可以看到duration就是根据period这个第一个字母(索引)的key去duration这个字典中取值,这里都是设置好的
        就是时分秒对应的秒数,这也是为什么我上面的duration说是60了因为对应的rate=5/m中的m就是minute分钟
        它这里的写法比较高级,直接取第一个字符,不管你后面写了什么只要对应上第一个字符就可以
        '''
        duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]

		'最后给这两个值返回出去'
        return (num_requests, duration)

文章来源:https://blog.csdn.net/achen_m/article/details/135341560
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。