Django Ratelimit
Django Ratelimit is a cache-based rate-limiting library for Django applications, currently at version 4.1.0. It provides decorators and middleware to limit the rate of client requests, helping to prevent abuse and manage server resources. The library typically has an active release cadence, with major versions aligning with Django's own release cycle and minor versions for fixes and features.
Warnings
- breaking The package name was changed from `ratelimit` to `django_ratelimit` in version 4.0.0. All import statements must be updated accordingly (e.g., `from django_ratelimit.decorators import ratelimit`).
- breaking The default behavior of the `@ratelimit` decorator's `block` argument changed from `False` to `True` in version 4.0.0. Views will now block requests by default if the rate limit is exceeded, instead of just annotating the request.
- breaking Version 4.0.0 dropped support for Python versions older than 3.7 and Django versions older than 3.2.
- gotcha `django-ratelimit` requires a Django cache backend that supports atomic increment operations (e.g., Memcached or Redis). The database cache backend does *not* support this and will lead to incorrect rate limiting behavior.
- deprecated Since version 3.0, the `@ratelimit` decorator no longer directly supports class methods, and `RatelimitMixin` was dropped. Instead, use `@method_decorator` for class-based views.
Install
-
pip install django-ratelimit
Imports
- ratelimit
from django_ratelimit.decorators import ratelimit
- ALL
from django_ratelimit import ALL, UNSAFE
Quickstart
from django.http import HttpResponse
from django.conf import settings
from django.core.cache import cache
from django_ratelimit.decorators import ratelimit
# Ensure Django settings are configured for a cache backend supporting atomic increments
# (e.g., Memcached or Redis).
# In a real project, this would be in settings.py
if not settings.configured:
settings.configure(
DEBUG=True,
SECRET_KEY='a-very-secret-key',
CACHES={
'default': {
'BACKEND': 'django.core.cache.backends.locmem.LocMemCache',
'LOCATION': 'unique-snowflake',
}
},
ROOT_URLCONF=__name__,
INSTALLED_APPS=[
'django_ratelimit'
]
)
# Clear cache for repeatable testing
cache.clear()
@ratelimit(key='ip', rate='5/m', block=True)
def my_rate_limited_view(request):
"""This view allows 5 requests per minute per IP address."""
return HttpResponse("Hello from a rate-limited view!")
# Example of how you might test it (not part of typical quickstart)
if __name__ == '__main__':
from django.urls import path
from django.test import RequestFactory
urlpatterns = [
path('limited/', my_rate_limited_view),
]
factory = RequestFactory()
for i in range(7):
request = factory.get('/limited/')
request.META['REMOTE_ADDR'] = '127.0.0.1' # Simulate client IP
try:
response = my_rate_limited_view(request)
print(f"Request {i+1}: Status {response.status_code}")
except Exception as e:
print(f"Request {i+1}: Blocked (Exception: {type(e).__name__})")