- class SimpleRateThrottle(BaseThrottle):
- """
A simple cache implementation, that only requires `.get_cache_key()`
to be overridden.
The rate (requests / seconds) is set by a `rate` attribute on the View
class. The attribute is a string of the form 'number_of_requests/period'.
Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day')
Previous request information used for throttling is stored in the cache.
- """
- 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):
- self.rate = self.get_rate()
- self.num_requests, self.duration = self.parse_rate(self.rate)
- def get_cache_key(self, request, view):
- """
Should return a unique cache-key which can be used for throttling.
Must be overridden.
May return `None` if the request should not be throttled.
- """raise NotImplementedError('.get_cache_key() must be overridden')
- def get_rate(self):
- """Determine the string representation of the allowed request rate."""
- if not getattr(self, 'scope', None):
- msg = ("You must set either `.scope` or `.rate` for'%s'throttle" %
- self.__class__.__name__)
- raise ImproperlyConfigured(msg)
- try:
- return self.THROTTLE_RATES[self.scope]
- except KeyError:
- msg = "No default throttle rate set for'%s'scope" % self.scope
- raise ImproperlyConfigured(msg)
- def parse_rate(self, rate):
- """
- Given the request rate string, return a two tuple of:
- <allowed number of requests>, <period of time in seconds>
- """
- if rate is None:
- return (None, None)
- num, period = rate.split('/')
- num_requests = int(num)
- duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
- return (num_requests, duration)
- def allow_request(self, request, view):
- """
Implement the check to see if the request should be throttled.
On success calls `throttle_success`.
On failure calls `throttle_failure`.
- """
- if self.rate is None:
- return True
- self.key = self.get_cache_key(request, view)
- if self.key is None:
- return True
- self.history = self.cache.get(self.key, [])
- self.now = self.timer()
- # Drop any requests from the history which have now passed the
- # throttle duration
- 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()
- return self.throttle_success()
- def throttle_success(self):
- """Inserts the current request's timestamp along with the key
into the cache.
- """
- self.history.insert(0, self.now)
- self.cache.set(self.key, self.history, self.duration)
- return True
- def throttle_failure(self):
- """Called when a request to the API has failed due to throttling."""
- return False
- def wait(self):
- """Returns the recommended next request time in seconds."""
- if self.history:
- remaining_duration = self.duration - (self.now - self.history[-1])
- else:
- remaining_duration = self.duration
- available_requests = self.num_requests - len(self.history) + 1
- if available_requests <= 0:
- return None
- return remaining_duration / float(available_requests)
来源: https://www.cnblogs.com/wdliu/p/9114537.html