django rest framework之节流的源码流程剖析

视图类:

 1 class UserViewset(BaseView):
 2     ‘‘‘
 3         create:
 4         创建用户
 5         retrieve:
 6
 7     ‘‘‘
 8     queryset = User.objects.all()
 9     throttle_classes = [UserRateThrottle] #添加节流类
10     authentication_classes = (JSONWebTokenAuthentication, authentication.SessionAuthentication)
11     def get_serializer_class(self):
12         self.dispatch
13         if self.action == "retrieve":
14             return UserDetailSerializer
15         elif self.action == "create":
16             return UserRegSerializer
17
18         return UserDetailSerializer
19
20     def get_permissions(self):
21         if self.action == "retrieve":
22             return [permissions.IsAuthenticated()]
23         elif self.action == "create":
24             return []
25
26         return []
27
28     def create(self, request, *args, **kwargs):
29         serializer = self.get_serializer(data=request.data)
30         serializer.is_valid(raise_exception=True)
31         user = self.perform_create(serializer)
32         re_dict = serializer.data
33         payload = jwt_payload_handler(user)
34         re_dict["token"] = jwt_encode_handler(payload)
35         re_dict["name"] = user.name if user.name else user.username
36
37         headers = self.get_success_headers(serializer.data)
38         return Response(re_dict, status=status.HTTP_201_CREATED, headers=headers)
39
40     def get_object(self):
41         return self.request.user
42
43     def perform_create(self, serializer):
44         return serializer.save()

通权限类一样在中调用:

1     def check_throttles(self, request):
2         """
3         Check if request should be throttled.
4         Raises an appropriate exception if the request is throttled.
5         """
6         for throttle in self.get_throttles():
7             if not throttle.allow_request(request, self): #验证是不是要被节流
8                 self.throttled(request, throttle.wait())  #验证不通过就返回响应

内置节流类:

  1 class BaseThrottle(object):
  2     """
  3     Rate throttling of requests.
  4     """
  5
  6     def allow_request(self, request, view):
  7         """
  8         Return `True` if the request should be allowed, `False` otherwise.
  9         """
 10         raise NotImplementedError(‘.allow_request() must be overridden‘)
 11
 12     def get_ident(self, request): 获取访问IP
 13         """
 14         Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
 15         if present and number of proxies is > 0. If not use all of
 16         HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
 17         """
 18         xff = request.META.get(‘HTTP_X_FORWARDED_FOR‘)
 19         remote_addr = request.META.get(‘REMOTE_ADDR‘)
 20         num_proxies = api_settings.NUM_PROXIES
 21
 22         if num_proxies is not None:
 23             if num_proxies == 0 or xff is None:
 24                 return remote_addr
 25             addrs = xff.split(‘,‘)
 26             client_addr = addrs[-min(num_proxies, len(addrs))]
 27             return client_addr.strip()
 28
 29         return ‘‘.join(xff.split()) if xff else remote_addr
 30
 31     def wait(self):
 32         """
 33         Optionally, return a recommended number of seconds to wait before
 34         the next request.
 35         """
 36         return None
 37
 38
 39 class SimpleRateThrottle(BaseThrottle):
 40     """
 41     A simple cache implementation, that only requires `.get_cache_key()`
 42     to be overridden.
 43
 44     The rate (requests / seconds) is set by a `rate` attribute on the View
 45     class.  The attribute is a string of the form ‘number_of_requests/period‘.
 46
 47     Period should be one of: (‘s‘, ‘sec‘, ‘m‘, ‘min‘, ‘h‘, ‘hour‘, ‘d‘, ‘day‘)
 48
 49     Previous request information used for throttling is stored in the cache.
 50     """
 51     cache = default_cache
 52     timer = time.time
 53     cache_format = ‘throttle_%(scope)s_%(ident)s‘
 54     scope = None
 55     THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES  #获取配置
 56
 57     def __init__(self):
 58         if not getattr(self, ‘rate‘, None):
 59             self.rate = self.get_rate()
 60         self.num_requests, self.duration = self.parse_rate(self.rate)
 61
 62     def get_cache_key(self, request, view):
 63         """
 64         Should return a unique cache-key which can be used for throttling.
 65         Must be overridden.
 66
 67         May return `None` if the request should not be throttled.
 68         """
 69         raise NotImplementedError(‘.get_cache_key() must be overridden‘)
 70
 71     def get_rate(self): #获取配置的参数
 72         """
 73         Determine the string representation of the allowed request rate.
 74         """
 75         if not getattr(self, ‘scope‘, None):
 76             msg = ("You must set either `.scope` or `.rate` for ‘%s‘ throttle" %
 77                    self.__class__.__name__)
 78             raise ImproperlyConfigured(msg)
 79
 80         try:
 81             return self.THROTTLE_RATES[self.scope]
 82         except KeyError:
 83             msg = "No default throttle rate set for ‘%s‘ scope" % self.scope
 84             raise ImproperlyConfigured(msg)
 85
 86     def parse_rate(self, rate): #获取定义里的节流策略如3/m,每分钟访问3次
 87         """
 88         Given the request rate string, return a two tuple of:
 89         <allowed number of requests>, <period of time in seconds>
 90         """
 91         if rate is None:
 92             return (None, None)
 93         num, period = rate.split(‘/‘)
 94         num_requests = int(num)
 95         duration = {‘s‘: 1, ‘m‘: 60, ‘h‘: 3600, ‘d‘: 86400}[period[0]]
 96         return (num_requests, duration)
 97
 98     def allow_request(self, request, view):
 99         """
100         Implement the check to see if the request should be throttled.
101
102         On success calls `throttle_success`.
103         On failure calls `throttle_failure`.
104         """
105         if self.rate is None:
106             return True
107
108         self.key = self.get_cache_key(request, view) #获取存储的key
109         if self.key is None:
110             return True
111
112         self.history = self.cache.get(self.key, []) #获取访问历史
113         self.now = self.timer()
114
115         # Drop any requests from the history which have now passed the
116         # throttle duration
117         while self.history and self.history[-1] <= self.now - self.duration:
118             self.history.pop()
119         if len(self.history) >= self.num_requests: #判断
120             return self.throttle_failure()
121         return self.throttle_success()
122
123     def throttle_success(self):
124         """
125         Inserts the current request‘s timestamp along with the key
126         into the cache.
127         """
128         self.history.insert(0, self.now)
129         self.cache.set(self.key, self.history, self.duration)
130         return True
131
132     def throttle_failure(self):
133         """
134         Called when a request to the API has failed due to throttling.
135         """
136         return False
137
138     def wait(self):  #返回响应
139         """
140         Returns the recommended next request time in seconds.
141         """
142         if self.history:
143             remaining_duration = self.duration - (self.now - self.history[-1])
144         else:
145             remaining_duration = self.duration
146
147         available_requests = self.num_requests - len(self.history) + 1
148         if available_requests <= 0:
149             return None
150
151         return remaining_duration / float(available_requests)
152 class UserRateThrottle(SimpleRateThrottle):
153     """
154     Limits the rate of API calls that may be made by a given user.
155
156     The user id will be used as a unique cache key if the user is
157     authenticated.  For anonymous requests, the IP address of the request will
158     be used.
159     """
160     scope = ‘user‘
161
162     def get_cache_key(self, request, view):
163         if request.user.is_authenticated:  #如果用户是登录后的就返回用户的id
164             ident = request.user.pk
165         else:
166             ident = self.get_ident(request) #返回请求的ip
167
168         return self.cache_format % {
169             ‘scope‘: self.scope,
170             ‘ident‘: ident
171         }

原文地址:https://www.cnblogs.com/arrow-kejin/p/9988271.html

时间: 2024-10-08 17:30:31

django rest framework之节流的源码流程剖析的相关文章

Django rest framework 限制访问频率(源码分析三)

基于 当用发出请求时 首先执行dispatch函数,当执行当第二部时: #2.处理版本信息 处理认证信息 处理权限信息 对用户的访问频率进行限制 self.initial(request, *args, **kwargs) 进入到initial方法: def initial(self, request, *args, **kwargs): """ Runs anything that needs to occur prior to calling the method han

Flask源码流程剖析

在此之前需要先知道类和方法,个人总结如下: 1.对象是类创建,创建对象时候类的__init__方法自动执行,对象()执行类的 __call__ 方法 2.类是type创建,创建类时候type的__init__方法自动执行,类() 执行type的 __call__方法(类的__new__方法,类的__init__方法) # 第0步: 执行type的 __init__ 方法[类是type的对象]class Foo:    def __init__(self):        pass def __c

Django学习【第29篇】:django-admin的源码流程

django-admin的源码流程 一.admin的源码流程 首先可以确定的是:路由关系一定对应一个视图函数 a.当点击运行的时候,会先找到每一个app中的admin.py文件,并执行 b.执行urls.py admin.site是什么? admin.site,urls    返回的是一个元组,里面的第一个元素是一个列表 django-admin的源码流程 我们自己生成的动态的访问url ====================================初级版===============

rest_framework-02-权限-内置权限源码流程

权限 问题:不同视图不同权限可以访问 1.models.py from django.db import models class UserInfo(models.Model): user_type_choices = ( (1,'普通用户'), (2,'VIP'), (3,'SVIP'), ) user_type = models.IntegerField(choices=user_type_choices) # username = models.CharField(max_length=3

django-admin的源码流程

django-admin的源码流程 一.admin的源码流程 首先可以确定的是:路由关系一定对应一个视图函数 a.当点击运行的时候,会先找到每一个app中的admin.py文件,并执行 b.执行urls.py admin.site是什么? admin.site,urls    返回的是一个元组,里面的第一个元素是一个列表 django-admin的源码流程 我们自己生成的动态的访问url ====================================初级版===============

【源码】StringBuilder和StringBuffer源码深度剖析

//------------------------------------------------------------------------ 写篇博客不容易,请尊重作者劳动成果.转载请注明出处:http://blog.csdn.net/chdjj //------------------------------------------------------------------------ 我觉得要通过源码研究一个类,应该先从整体上了解这个类,比如说这个类的继承体系,有哪些超类,继承

onLayout源码 流程 思路详解(ANDROID自定义视图)

简介: 在自定义view的时候,其实很简单,只需要知道3步骤: 1.测量--onMeasure():决定View的大小 2.布局--onLayout():决定View在ViewGroup中的位置 3.绘制--onDraw():如何绘制这个View. 而第3步的onDraw系统已经封装的很好了,基本不用我们来操心,只需要专注到1,2两个步骤就中好了. 第一步的测量,可以参考我之前的文章:(ANDROID自定义视图--onMeasure流程,MeasureSpec详解) 而这篇文章就来谈谈第二步:"

libevent源码深度剖析

libevent 源码深度剖析,from: blog.csdn.net/sparkliang/article/category/660506 http://download.csdn.net/detail/sparkliang/2001038#comment http://libevent.org/

libevent 源码深度剖析十三

libevent 源码深度剖析十三 -- libevent 信号处理注意点 前面讲到了 libevent 实现多线程的方法,然而在多线程的环境中注册信号事件,还是有一些情况需要小心处理,那就是不能在多个 libevent 实例上注册信号事件.依然冠名追加到 libevent 系列. 以 2 个线程为例,做简单的场景分析. 1 首先是创建并初始化线程 1 的 libevent 实例 base1 ,线程 1 的 libevent 实例 base2 : 2 在 base1 上注册 SIGALRM 信号