mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-07-28 08:59:54 +03:00
Additional throttle rate configurability
This commit is contained in:
parent
0dac98d215
commit
dd7adc7ed7
|
@ -41,7 +41,7 @@ The default throttling policy may be set globally, using the `DEFAULT_THROTTLE_C
|
|||
}
|
||||
}
|
||||
|
||||
The rate descriptions used in `DEFAULT_THROTTLE_RATES` may include `second`, `minute`, `hour` or `day` as the throttle period.
|
||||
The rate descriptions used in `DEFAULT_THROTTLE_RATES` may include `second`, `minute`, `hour` or `day` as the throttle period. To set the rate to a fraction of a period, simply prepend the desired timespan. For example, a rate of `'100/30s'` will mean "limit requests to a maximum of 100 per every 30 seconds".
|
||||
|
||||
You can also set the throttling policy on a per-view or per-viewset basis,
|
||||
using the `APIView` class-based views.
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
"""
|
||||
Provides various throttling policies.
|
||||
"""
|
||||
import re
|
||||
import time
|
||||
|
||||
from django.core.cache import cache as default_cache
|
||||
|
@ -101,9 +102,26 @@ class SimpleRateThrottle(BaseThrottle):
|
|||
"""
|
||||
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]]
|
||||
|
||||
try:
|
||||
num, period = rate.split('/')
|
||||
num_requests = int(num)
|
||||
# Get rate multiplier value if available
|
||||
period_mult, _ = re.split('[s|m|h|d]', period, maxsplit=1)
|
||||
period_char = re.findall('[s|m|h|d]', period)[0]
|
||||
except ValueError:
|
||||
msg = "Incorrect throttle rate set for '%s' scope" % self.scope
|
||||
raise ImproperlyConfigured(msg)
|
||||
|
||||
try:
|
||||
period_mult = int(period_mult)
|
||||
except ValueError:
|
||||
period_mult = 1
|
||||
|
||||
duration = {'s': 1 * period_mult,
|
||||
'm': 60 * period_mult,
|
||||
'h': 3600 * period_mult,
|
||||
'd': 86400 * period_mult}[period_char]
|
||||
return (num_requests, duration)
|
||||
|
||||
def allow_request(self, request, view):
|
||||
|
|
|
@ -451,6 +451,9 @@ class SimpleRateThrottleTests(TestCase):
|
|||
def setUp(self):
|
||||
SimpleRateThrottle.scope = 'anon'
|
||||
|
||||
def tearDown(self):
|
||||
SimpleRateThrottle.rate = None
|
||||
|
||||
def test_get_rate_raises_error_if_scope_is_missing(self):
|
||||
throttle = SimpleRateThrottle()
|
||||
with pytest.raises(ImproperlyConfigured):
|
||||
|
@ -462,6 +465,48 @@ class SimpleRateThrottleTests(TestCase):
|
|||
with pytest.raises(ImproperlyConfigured):
|
||||
SimpleRateThrottle()
|
||||
|
||||
def test_throttle_raises_error_if_rate_is_incorrect(self):
|
||||
SimpleRateThrottle.rate = 'rate'
|
||||
with pytest.raises(ImproperlyConfigured):
|
||||
SimpleRateThrottle()
|
||||
|
||||
SimpleRateThrottle.rate = 'rate/hour'
|
||||
with pytest.raises(ImproperlyConfigured):
|
||||
SimpleRateThrottle()
|
||||
|
||||
SimpleRateThrottle.rate = '100/century'
|
||||
with pytest.raises(ImproperlyConfigured):
|
||||
SimpleRateThrottle()
|
||||
|
||||
SimpleRateThrottle.rate = '100/10century'
|
||||
with pytest.raises(ImproperlyConfigured):
|
||||
SimpleRateThrottle()
|
||||
|
||||
def test_parse_rate_returns_correct_rate(self):
|
||||
rate_str = '10/h'
|
||||
SimpleRateThrottle.rate = rate_str
|
||||
rate = SimpleRateThrottle().parse_rate(rate_str)
|
||||
assert rate == (10, 3600)
|
||||
|
||||
rate_str = '30/hour'
|
||||
SimpleRateThrottle.rate = rate_str
|
||||
rate = SimpleRateThrottle().parse_rate(rate_str)
|
||||
assert rate == (30, 3600)
|
||||
|
||||
rate_str = '30/10min'
|
||||
SimpleRateThrottle.rate = rate_str
|
||||
rate = SimpleRateThrottle().parse_rate(rate_str)
|
||||
assert rate == (30, 10 * 60)
|
||||
|
||||
rate_str = '100/30seconds'
|
||||
SimpleRateThrottle.rate = rate_str
|
||||
rate = SimpleRateThrottle().parse_rate(rate_str)
|
||||
assert rate == (100, 30)
|
||||
|
||||
SimpleRateThrottle.rate = '100/10d'
|
||||
rate = SimpleRateThrottle().parse_rate('100/10d')
|
||||
assert rate == (100, 10 * 86400)
|
||||
|
||||
def test_parse_rate_returns_tuple_with_none_if_rate_not_provided(self):
|
||||
rate = SimpleRateThrottle().parse_rate(None)
|
||||
assert rate == (None, None)
|
||||
|
|
Loading…
Reference in New Issue
Block a user