A comprehensive Django rate limiter with multiple algorithms and storage backends
Project description
Django Rate Limiter
A comprehensive Django rate limiter with multiple algorithms and storage backends, designed for high-performance applications with thread safety and deadlock prevention.
🚀 Features
- Multiple Rate Limiting Algorithms: Sliding window, token bucket, fixed window, sliding window counter
- Thread-Safe & Deadlock-Safe: Proper locking mechanisms prevent race conditions
- Multiple Storage Backends: In-memory, database, Redis - choose what fits your needs
- Django Integration: Decorators, middleware, management commands
- High Performance: Optimized for high-throughput scenarios
- Flexible Configuration: Per-endpoint, per-user, per-IP, or custom key functions
📦 Installation
pip install django-rate-limiter-goosebumps
For Redis support:
pip install redis
⚡ Quick Start
1. Add to Django Settings
# settings.py
INSTALLED_APPS = [
# ... your other apps
'django_rate_limiter',
]
2. Choose Your Storage Backend
Memory Backend (Development)
RATE_LIMIT_SETTINGS = {
'BACKEND': 'memory', # Fast, simple, not persistent
'GLOBAL_LIMIT': 1000,
'GLOBAL_WINDOW': 3600,
}
Database Backend (Single Server)
RATE_LIMIT_SETTINGS = {
'BACKEND': 'database', # Persistent, works across restarts
'GLOBAL_LIMIT': 1000,
'GLOBAL_WINDOW': 3600,
}
Run migrations for database backend:
python manage.py migrate django_rate_limiter
Redis Backend (Distributed/High Performance)
RATE_LIMIT_SETTINGS = {
'BACKEND': 'redis', # Fast, distributed, scalable
'BACKEND_KWARGS': {
'host': 'localhost',
'port': 6379,
'db': 0,
},
'GLOBAL_LIMIT': 1000,
'GLOBAL_WINDOW': 3600,
}
3. Use Decorators
from django_rate_limiter.decorators import rate_limit, throttle
@rate_limit(limit=100, window=3600) # 100 requests per hour
def my_api_view(request):
return JsonResponse({"message": "Hello world"})
@throttle("10/minute") # 10 requests per minute
def strict_endpoint(request):
return JsonResponse({"data": "limited access"})
🔧 Backend Configuration Guide
When to Use Each Backend
| Backend | Best For | Persistence | Multi-Process | Performance | Setup |
|---|---|---|---|---|---|
| Memory | Development, testing | ❌ | ❌ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ |
| Database | Single server production | ✅ | ✅ | ⭐⭐⭐ | ⭐⭐⭐⭐ |
| Redis | Distributed systems | ✅ | ✅ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
Detailed Backend Configuration
Memory Backend
# settings.py
RATE_LIMIT_SETTINGS = {
'BACKEND': 'memory',
'DEFAULT_ALGORITHM': 'sliding_window',
'GLOBAL_LIMIT': 1000,
'GLOBAL_WINDOW': 3600,
}
Pros: Fastest performance, no external dependencies
Cons: Data lost on restart, single process only
Database Backend
# settings.py
RATE_LIMIT_SETTINGS = {
'BACKEND': 'database',
'DEFAULT_ALGORITHM': 'sliding_window',
'GLOBAL_LIMIT': 1000,
'GLOBAL_WINDOW': 3600,
}
Setup required:
python manage.py migrate django_rate_limiter
python manage.py cleanup_rate_limits # Optional cleanup command
Pros: Persistent across restarts, works with existing Django database
Cons: Slower than memory/Redis, database overhead
Redis Backend
# settings.py
RATE_LIMIT_SETTINGS = {
'BACKEND': 'redis',
'BACKEND_KWARGS': {
'host': 'localhost',
'port': 6379,
'db': 0,
'password': None, # Set if Redis requires auth
},
'DEFAULT_ALGORITHM': 'sliding_window',
'GLOBAL_LIMIT': 1000,
'GLOBAL_WINDOW': 3600,
}
Pros: Very fast, distributed, highly scalable
Cons: Requires Redis server setup
📚 Usage Examples
Decorator Usage
from django_rate_limiter.decorators import rate_limit, throttle, per_user_rate_limit
# Basic rate limiting
@rate_limit(limit=100, window=3600) # 100 requests per hour
def api_endpoint(request):
return JsonResponse({"data": "response"})
# Using different backends
@rate_limit(limit=50, window=300, backend="database")
def persistent_endpoint(request):
return JsonResponse({"message": "Stored in database"})
@rate_limit(limit=1000, window=3600, backend="redis")
def high_traffic_endpoint(request):
return JsonResponse({"message": "Fast Redis storage"})
# Different algorithms
@rate_limit(limit=10, window=60, algorithm="token_bucket")
def burst_allowed_endpoint(request):
return JsonResponse({"message": "Allows burst traffic"})
# Simple throttling
@throttle("10/minute")
def simple_throttled_view(request):
return JsonResponse({"message": "10 per minute max"})
# Per-user rate limiting
@per_user_rate_limit(limit=1000, window=3600)
def user_api(request):
return JsonResponse({"user": str(request.user)})
MIDDLEWARE = [
# ... other middleware
'django_rate_limiter.middleware.RateLimitMiddleware',
]
RATE_LIMIT_SETTINGS = {
'BACKEND': 'memory', # 'memory', 'database', 'redis'
'DEFAULT_ALGORITHM': 'sliding_window',
'RULES': [
{
'path_pattern': r'^/api/',
'limit': 1000,
'window': 3600,
'algorithm': 'sliding_window',
'scope': 'api',
},
{
'path_pattern': r'^/login/$',
'limit': 5,
'window': 300,
'algorithm': 'fixed_window',
'use_user': False, # Use IP instead of user
},
],
'GLOBAL_LIMIT': 10000,
'GLOBAL_WINDOW': 3600,
'EXEMPT_PATHS': [r'^/health/$', r'^/static/'],
'EXEMPT_IPS': ['127.0.0.1', '::1'],
'USE_USER_ID': True,
'RATE_LIMIT_HEADERS': True,
}
Programmatic Usage
from django_rate_limiter import check_rate_limit, RateLimitExceeded
try:
metadata = check_rate_limit(
identifier="user:123",
limit=100,
window=3600,
algorithm="token_bucket",
backend="redis"
)
print(f"Remaining requests: {metadata['remaining']}")
except RateLimitExceeded as e:
print(f"Rate limit exceeded! Retry after: {e.retry_after} seconds")
Rate Limiting Algorithms
1. Sliding Window
Maintains exact request timestamps for precise rate limiting:
@rate_limit(limit=100, window=3600, algorithm="sliding_window")
def precise_api_view(request):
return JsonResponse({"data": "response"})
Pros: Precise, no burst at window boundaries
Cons: Higher memory usage
2. Token Bucket
Allows controlled bursts while maintaining steady rate:
@rate_limit(
limit=60, # 60 tokens per hour
window=3600,
algorithm="token_bucket",
burst_capacity=100 # Can burst up to 100 requests
)
def bursty_api_view(request):
return JsonResponse({"data": "response"})
Pros: Allows bursts, smooth rate limiting
Cons: More complex logic
3. Fixed Window
Simple counter reset at fixed intervals:
@rate_limit(limit=1000, window=3600, algorithm="fixed_window")
def simple_api_view(request):
return JsonResponse({"data": "response"})
Pros: Simple, memory efficient
Cons: Potential bursts at window boundaries
4. Sliding Window Counter
Approximates sliding window using multiple counters:
@rate_limit(
limit=1000,
window=3600,
algorithm="sliding_counter",
num_windows=12 # 12 5-minute windows
)
def balanced_api_view(request):
return JsonResponse({"data": "response"})
Pros: Good balance of accuracy and efficiency
Cons: Approximation, not exact
Storage Backends
Memory Backend
Fast, single-server storage:
@rate_limit(limit=100, window=3600, backend="memory")
def memory_limited_view(request):
return JsonResponse({"data": "response"})
Database Backend
Persistent storage using Django ORM:
@rate_limit(limit=100, window=3600, backend="database")
def db_limited_view(request):
return JsonResponse({"data": "response"})
Redis Backend
Distributed, high-performance storage:
@rate_limit(
limit=100,
window=3600,
backend="redis",
backend_kwargs={
'host': 'localhost',
'port': 6379,
'db': 0,
'password': 'your-password'
}
)
def redis_limited_view(request):
return JsonResponse({"data": "response"})
Advanced Usage
Custom Rate Limiting Keys
def api_key_extractor(request):
return request.META.get('HTTP_X_API_KEY', 'anonymous')
@custom_key_rate_limit(api_key_extractor, limit=1000, window=3600)
def api_key_limited_view(request):
return JsonResponse({"data": "response"})
Rate Limiting Decorators
# Per user rate limiting
@per_user_rate_limit(limit=1000, window=3600)
def user_limited_view(request):
return JsonResponse({"data": "response"})
# Per IP rate limiting
@per_ip_rate_limit(limit=100, window=3600)
def ip_limited_view(request):
return JsonResponse({"data": "response"})
# Simple throttling with rate strings
@throttle("100/hour", algorithm="token_bucket")
def throttled_view(request):
return JsonResponse({"data": "response"})
Class-Based Views
from django.views import View
from django_rate_limiter import rate_limit_class
@rate_limit_class(limit=100, window=3600, methods=['GET', 'POST'])
class MyAPIView(View):
def get(self, request):
return JsonResponse({"method": "GET"})
def post(self, request):
return JsonResponse({"method": "POST"})
Management Commands
Clean up expired rate limit entries:
# Dry run (show what would be deleted)
python manage.py cleanup_rate_limits --dry-run
# Actually delete expired entries
python manage.py cleanup_rate_limits
Configuration
Complete Settings Example
RATE_LIMIT_SETTINGS = {
# Backend configuration
'BACKEND': 'redis', # 'memory', 'database', 'redis'
'BACKEND_KWARGS': {
'host': 'localhost',
'port': 6379,
'db': 0,
},
# Default algorithm
'DEFAULT_ALGORITHM': 'sliding_window',
# Path-specific rules
'RULES': [
{
'path_pattern': r'^/api/v1/',
'limit': 1000,
'window': 3600,
'algorithm': 'sliding_window',
'scope': 'api_v1',
},
{
'path_pattern': r'^/api/v2/',
'limit': 2000,
'window': 3600,
'algorithm': 'token_bucket',
'scope': 'api_v2',
'burst_capacity': 100,
},
{
'path_pattern': r'^/auth/',
'limit': 10,
'window': 300,
'algorithm': 'fixed_window',
'use_user': False, # Use IP for auth endpoints
},
],
# Global limits
'GLOBAL_LIMIT': 10000,
'GLOBAL_WINDOW': 3600,
# Exemptions
'EXEMPT_PATHS': [
r'^/health/$',
r'^/static/',
r'^/media/',
],
'EXEMPT_IPS': ['127.0.0.1', '::1'],
# Behavior settings
'USE_USER_ID': True, # Use authenticated user ID when available
'RATE_LIMIT_HEADERS': True, # Add X-RateLimit-* headers
}
Thread Safety & Performance
This package is designed with thread safety and performance in mind:
- Memory Backend: Uses
threading.RLock()to prevent deadlocks - Database Backend: Uses
select_for_update()for atomic operations - Redis Backend: Uses Redis transactions and watches for atomic updates
- Algorithms: All algorithms use atomic operations to prevent race conditions
Contributing
- Fork the repository
- Create your feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Testing
Run the test suite:
# Install test dependencies
pip install -e .[dev]
# Run tests
pytest
# Run tests with coverage
pytest --cov=django_rate_limiter-goosebumps --cov-report=html
Development Tools 🛠️
This project includes comprehensive development tools to ensure code quality:
# Quick setup
./setup-dev.sh
# Run all quality checks
./check-code.sh # Shell script
python check_quality.py # Python script
make check # Makefile
# Pre-commit hooks (automatic)
pre-commit install
For detailed information about development tools, see DEV_TOOLS.md.
License
This project is licensed under the MIT License - see the LICENSE file for details.
Changelog
Version 1.0.0
- Initial release
- Multiple rate limiting algorithms (sliding window, token bucket, fixed window, sliding counter)
- Multiple storage backends (memory, database, Redis)
- Thread-safe and deadlock-safe implementation
- Django decorators and middleware
- Management commands
- Comprehensive test suite
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file django_rate_limiter_goosebumps-1.0.2.tar.gz.
File metadata
- Download URL: django_rate_limiter_goosebumps-1.0.2.tar.gz
- Upload date:
- Size: 27.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d18ae741c0e31396a625318d16551f3bca50d2bec0fc3c58285955d70225c2c4
|
|
| MD5 |
87e13853c2c834e9ac31c96f8c82866d
|
|
| BLAKE2b-256 |
60bcfdb572641f66a8b3b401c8a59983da81e2413116ccd4f318dfad94174110
|
File details
Details for the file django_rate_limiter_goosebumps-1.0.2-py3-none-any.whl.
File metadata
- Download URL: django_rate_limiter_goosebumps-1.0.2-py3-none-any.whl
- Upload date:
- Size: 24.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.10.18
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
cf8fb2c47a8b9b7f52889719a6214f27d5267fc490d7a8c30a7949e9abcd8af0
|
|
| MD5 |
66579ed92daea050adc00ecdde3d0d91
|
|
| BLAKE2b-256 |
27b0b8a8f866d07096db4c90cfdf8895767ee909d8252aee188f92f5398474b3
|