Throttling
API rate limiting is a technique used to control the number of requests a user or client can make to an API within a specific time frame. In Django, you can implement rate limiting using third-party libraries like Django REST Framework’s (DRF) throttling or by integrating specialized libraries like django-ratelimit.
4.1 Using Django REST Framework (DRF) Throttling
DRF provides built-in throttling classes to enforce rate limits.
Period should be one of: (’s’, ‘sec’, ’m’, ‘min’, ‘h’, ‘hour’, ’d’, ‘day’)
4.2 Enable Throttling in Settings
The default throttling policy may be set globally, using the DEFAULT_THROTTLE_CLASSES and DEFAULT_THROTTLE_RATES settings
# setting.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.UserRateThrottle',
'rest_framework.throttling.AnonRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'user': '100/day', # 100 requests per day per user
'anon': '10/hour', # 10 requests per hour for unauthenticated users
},
}
AnonRateThrottle
The AnonRateThrottle will only ever throttle unauthenticated users
.
The IP address of the incoming request is used to generate a unique key to throttle against.
The allowed request rate is determined from one of the following (in order of preference).
The rate property on the class, which may be provided by overriding AnonRateThrottle and setting the property.
The DEFAULT_THROTTLE_RATES['anon']
setting.
AnonRateThrottle is suitable if you want to restrict the rate of requests from unknown sources.
UserRateThrottle
The UserRateThrottle will throttle users to a given rate of requests across the API. The user id is used to generate a unique key to throttle against.
Unauthenticated requests will fall back to using the IP address of the incoming request to generate a unique key to throttle against.
- The rate property on the class, which may be provided by overriding UserRateThrottle and setting the property.
- The
DEFAULT_THROTTLE_RATES['user']
setting.
4.3 Apply Throttling in Views
DRF automatically applies throttling to API views based on the settings. You can also customize throttling for specific views.
# setting.py
'DEFAULT_THROTTLE_RATES': {
'anon': '30/minute',
'user': '60/minute'
}
# views.py
from rest_framework import throttling
from rest_framework.decorators import throttle_classes
@api_view(['GET'])
@throttle_classes([throttling.UserRateThrottle])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
ScopedRateThrottle
ScopedRateThrottle is a built-in throttling class provided by Django REST Framework (DRF) to define rate limits based on scopes.
- Override UserRateThrottle/AnonRateThrottle is not required
- Can have combined count of a scope
# setting.py
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.ScopedRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'contacts': '50/day',
'uploads': '20/day'
}
}
# views.py
class ContactListView(APIView):
throttle_scope = 'contacts'
...
class ContactDetailView(APIView):
throttle_scope = 'contacts'
...
class UploadView(APIView):
throttle_scope = 'uploads'
- User requests to either ContactListView or ContactDetailView would be restricted to a total of 50 requests per day.
- User requests to UploadView would be restricted to 20 requests per day.
4.4 Define Custom Scope Rates
Add the custom_scope to the DEFAULT_THROTTLE_RATES.
- Create new throttling class
# setting.py
'DEFAULT_THROTTLE_RATES': {
'anon': '30/minute',
'user': '60/minute',
'cust_anon': '100/minute',
}
# views.py
from rest_framework import throttling
class CustomAnonRateThrottle(throttling.AnonRateThrottle):
scope = 'cust_anon'
def throttle_failure(self):
return False
def allow_request(self, request, view):
return super().allow_request(request, view)
@api_view(['GET'])
@throttle_classes([CustomAnonRateThrottle])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
Alternative ways
- Only update the throttling rate for a view
- Old rate: 30/min
- New rate: 7/day
# setting.py
'DEFAULT_THROTTLE_RATES': {
'anon': '30/minute',
'user': '60/minute'
}
# views.py
from rest_framework import throttling
class CustomAnononymousRateThrottle(throttling.AnonRateThrottle):
"""
specify a different rate for a specific view,
we can do this by extending the UserRateThrottle class
and specifying a new rate.
ISSUE:
Expected available(Time): is not always displayed
Rate: rate is not exact, always less the n defined
"""
rate = '7/day'
@api_view(['GET'])
@throttle_classes([CustomAnononymousRateThrottle])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)