Powerful decorators & utilities for Django developers. Rate limiting, caching, auth, CORS, pagination, retry & more in one package.
Project description
djhero
Powerful decorators & utilities for Django developers. One package, zero hassle.
Stop installing 5+ different packages for common Django patterns. djhero gives you 24 decorators, 5 utilities, and 5 signals — all production-ready.
Install
pip install djhero
Quick Start
from djhero import (
rate_limit, cache_view, log_request, auth_required,
json_response, validate_json, handle_exceptions, cors,
)
@rate_limit("100/h")
@cache_view(ttl=300)
@log_request
@cors()
@handle_exceptions
def product_list(request):
products = Product.objects.all()
return JsonResponse({"products": list(products.values())})
@auth_required()
@validate_json("name", "email")
@json_response
def create_user(request):
data = request.json_data
user = User.objects.create(name=data["name"], email=data["email"])
return {"id": user.id, "created": True}, 201
Decorators
Caching
@cache_view(ttl=300, key_prefix="djhero")
Cache view responses automatically.
@cache_view(ttl=60)
def my_view(request):
...
@cache_per_user(ttl=300)
Cache responses per authenticated user.
@cache_per_user(ttl=120)
def user_dashboard(request):
...
Rate Limiting
@rate_limit(limit, key_func=None, message=None)
Limit requests per time window. Adds X-RateLimit-Limit and X-RateLimit-Remaining headers.
@rate_limit("100/h") # 100 per hour
@rate_limit("10/m") # 10 per minute
@rate_limit("1000/d") # 1000 per day
@rate_limit("5/s") # 5 per second
# Custom key:
@rate_limit("100/h", key_func=lambda r: r.user.id)
@throttle(rate, key_func=None, message=None)
Enforce minimum interval between requests.
@throttle("1/s")
@throttle("5/m")
Auth & Permissions
@auth_required(login_url=None, message=None)
Require authentication. Returns JSON 401 for AJAX, redirects for browser.
@auth_required()
@auth_required(login_url="/login/", message="Please log in")
@permission_required(*perms, message=None)
@permission_required("app.can_edit", "app.can_delete")
@staff_required
@staff_required
def admin_panel(request):
...
@superuser_required
@superuser_required
def danger_zone(request):
...
Request Handling
@json_response
Automatically convert dict/list returns to JsonResponse.
@json_response
def my_view(request):
return {"message": "hello"} # -> JsonResponse 200
return {"created": True}, 201 # -> JsonResponse 201
return [1, 2, 3] # -> JsonResponse(safe=False)
@validate_json(*required_fields)
Validate JSON body and attach parsed data to request.json_data.
@validate_json("name", "email")
def create(request):
data = request.json_data # already parsed & validated
@require_fields(*fields, source="POST")
@require_fields("username", "password", source="POST")
@require_fields("q", source="GET")
@handle_exceptions
Catch exceptions and return JSON error response.
@handle_exceptions
@handle_exceptions(log_errors=True, default_status=500)
@timeout(seconds=30, message=None)
@timeout(seconds=5)
def slow_view(request):
...
@log_request / @log_request(level, log_body)
Log method, path, status, duration, IP. Adds X-Response-Time header.
@log_request
@log_request(level=logging.DEBUG, log_body=True)
@ajax_required
@ajax_required
def api_endpoint(request):
...
@method_required(*methods)
@method_required("GET", "POST")
@disable_csrf
@disable_csrf
def webhook(request):
...
HTTP Features
@cors(origins, methods, headers, max_age)
@cors() # Allow all
@cors(origins="https://example.com") # Specific origin
@cors(origins=["https://a.com", "https://b.com"]) # Multiple origins
@paginate(per_page=20, max_per_page=100)
Adds request.page, request.per_page, request.offset.
@paginate(per_page=25)
def list_view(request):
items = Item.objects.all()[request.offset:request.offset + request.per_page]
@etag(etag_func)
ETag support for conditional GET requests.
@etag(lambda req: hashlib.md5(str(req.GET).encode()).hexdigest())
def my_view(request):
...
@deprecated(message, sunset_date)
Adds Deprecation and Sunset headers.
@deprecated("Use /api/v2/users instead", sunset_date="2025-12-31")
@retry_on_error(max_retries=3, delay=0.5, exceptions=(Exception,))
@retry_on_error(max_retries=3, exceptions=(ConnectionError,))
def external_api(request):
...
@query_debugger
Log and count DB queries. Adds X-Query-Count and X-Query-Time headers.
@query_debugger
@query_debugger(warn_threshold=5)
Utilities
from djhero import success_response, error_response, paginated_response, get_json_body, get_client_ip
# Standardized responses
return success_response({"user": user_data}, message="Created", status=201)
return error_response("Not found", status=404)
return error_response("Validation failed", errors={"email": "Invalid"}, status=422)
# Paginated queryset response
return paginated_response(User.objects.all(), page=1, per_page=10)
# Parse JSON body safely
data = get_json_body(request, default={})
# Get client IP
ip = get_client_ip(request)
Signals
Listen to djhero events:
from djhero import rate_limit_exceeded, auth_failed, view_timeout, view_exception, deprecated_view_accessed
@receiver(rate_limit_exceeded)
def on_rate_limit(sender, request, limit, ip, **kwargs):
notify_admin(f"Rate limit hit by {ip}")
@receiver(view_exception)
def on_error(sender, request, exception, **kwargs):
send_to_sentry(exception)
@receiver(deprecated_view_accessed)
def on_deprecated(sender, request, message, **kwargs):
log_deprecated_usage(request.path)
Composing Decorators
Stack them freely:
@rate_limit("50/h")
@auth_required()
@cache_view(ttl=120)
@cors()
@log_request
@handle_exceptions
@timeout(seconds=10)
@json_response
def api_view(request):
return {"data": "fast & safe"}
Requirements
- Python 3.8+
- Django 4.0+
License
MIT
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 djhero-0.2.0.tar.gz.
File metadata
- Download URL: djhero-0.2.0.tar.gz
- Upload date:
- Size: 16.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
82fb0d2c3f81243b1a526c1410fb6ebc4800179a15dc535c9c224054b0c8a5e7
|
|
| MD5 |
6377bf5c6027833125a5c58c8ad5448e
|
|
| BLAKE2b-256 |
0bc831796cc690e37d52c3b5fa2b5d7e40b36e0edaf4adeb8e2d04d6e4183c10
|
File details
Details for the file djhero-0.2.0-py3-none-any.whl.
File metadata
- Download URL: djhero-0.2.0-py3-none-any.whl
- Upload date:
- Size: 12.0 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e5f304f7e4228ab12e00a7008cf94d89e9dc9a28ec010d42a8b2e71a1cd0dfd8
|
|
| MD5 |
8fa62b0954e4441debd456cd39724ee5
|
|
| BLAKE2b-256 |
707765750b971bd465ac588014df6fefd3190eb19f229c95df2d3ae3006cbebd
|