https://github.com/andriykohut/django-ratelimiter
Granular rate limiting for django
https://github.com/andriykohut/django-ratelimiter
django rate-limit rate-limiter rate-limiting ratelimit ratelimiter
Last synced: 6 months ago
JSON representation
Granular rate limiting for django
- Host: GitHub
- URL: https://github.com/andriykohut/django-ratelimiter
- Owner: andriykohut
- License: mit
- Created: 2024-04-10T19:29:22.000Z (over 1 year ago)
- Default Branch: main
- Last Pushed: 2025-03-24T12:43:02.000Z (7 months ago)
- Last Synced: 2025-03-25T16:45:00.773Z (6 months ago)
- Topics: django, rate-limit, rate-limiter, rate-limiting, ratelimit, ratelimiter
- Language: Python
- Homepage: https://andriykohut.github.io/django-ratelimiter/
- Size: 1020 KB
- Stars: 3
- Watchers: 2
- Forks: 0
- Open Issues: 5
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# django-ratelimiter
[](https://pypi.org/project/django-ratelimiter/)
[](https://github.com/andriykohut/django-ratelimiter/actions/workflows/ci.yml?query=branch%3Amain)
[](https://codecov.io/gh/andriykohut/django-ratelimiter)
[](https://pypi.python.org/pypi/django-ratelimiter/)
[](https://pypi.python.org/pypi/django-ratelimiter)
[](https://andriykohut.github.io/django-ratelimiter/)Rate limiting for django using [limits](https://limits.readthedocs.io/en/stable/).
Documentation:
## Installation
```py
pip install django-ratelimiter
```## Usage
By default `django-ratelimiter` will use the default cache.
### Django configuration
To use a non-default cache define `DJANGO_RATELIMITER_CACHE` in `settings.py`.
```py
# Set up django caches
CACHES = {
"custom-cache": {
"BACKEND": "django.core.cache.backends.redis.RedisCache",
"LOCATION": "redis://127.0.0.1:6379",
}
}# "default" cache is used if setting is not defined.
DJANGO_RATELIMITER_CACHE = "custom-cache"
```Any storage backend provided by `limits` package can also be used by defining `DJANGO_RATELIMITER_STORAGE`:
```py
from limits.storage import RedisStorageDJANGO_RATELIMITER_STORAGE = RedisStorage(uri="redis://localhost:6379/0")
```For more details on storages refer to limits [documentation](https://limits.readthedocs.io/en/stable/storage.html).
### Rate limiting strategies
- [Fixed window](https://limits.readthedocs.io/en/stable/strategies.html#fixed-window)
- [Fixed Window with Elastic Expiry](https://limits.readthedocs.io/en/stable/strategies.html#fixed-window-with-elastic-expiry)
- [Moving Window](https://limits.readthedocs.io/en/stable/strategies.html#moving-window) - Only supported with `limits` storage by setting `DJANGO_RATELIMITER_STORAGE`### View decorator
By default all requests are rate limited
```py
from django_ratelimiter import ratelimit@ratelimit("5/minute")
def view(request: HttpRequest) -> HttpResponse:
return HttpResponse("OK")
```Pick a rate limiting strategy, default is `fixed-window`:
```py
# options: fixed-window, fixed-window-elastic-expiry, moving-window
@ratelimit("5/minute", strategy="fixed-window-elastic-expiry")
def view(request: HttpRequest) -> HttpResponse:
return HttpResponse("OK")
```You can define per-user limits using request attribute key.
```py
@ratelimit("5/minute", key="user")
def view(request: HttpRequest) -> HttpResponse:
return HttpResponse("OK")
```Callable key can be used to define more complex rules:
```py
@ratelimit("5/minute", key=lambda r: r.user.username)
def view(request: HttpRequest) -> HttpResponse:
return HttpResponse("OK")
```Rate-limit only certain methods:
```py
@ratelimit("5/minute", methods=["POST", "PUT"])
def view(request):
return HttpResponse("OK")
```Provide a custom response:
```py
from django.http import HttpResponse@ratelimit("5/minute", response=HttpResponse("Too many requests", status=400))
def view(request):
return HttpResponse("OK")
```Using non-default storage:
```py
from limits.storage import RedisStorage
@ratelimit("5/minute", storage=RedisStorage(uri="redis://localhost:6379/0"))
def view(request):
return HttpResponse("OK")
```### Middleware
Middleware can be used instead of decorators for more general cases.
```py
from typing import Optionalfrom django.http import HttpRequest
from django_ratelimiter.middleware import AbstractRateLimiterMiddleware
class RateLimiterMiddleware(AbstractRateLimiterMiddleware):
def rate_for(self, request: HttpRequest) -> Optional[str]:
# allow only 100 POST requests per minute
if request.method == "POST":
return "100/minute"
# allow only 200 PUT requests per minute
if request.methid == "PUT":
return "200/minute"
# all other requests are not rate limited
return None
```Middleware is customizable by overriding methods, see api reference for more details.
### DRF/ninja/class-based views
`django-ratelimiter` is framework-agnostic, it should work with DRF/ninja out of the box.
Class-based views are also supported with [method_decorator](https://docs.djangoproject.com/en/5.0/topics/class-based-views/intro/#decorating-the-class).See examples in [test_app](./test_app/views.py).