Interview question
How do you create custom decorators for Django views to handle authentication, logging, and rate limiting? Django views के लिए custom decorators कैसे बनाते हैं - authentication, logging, rate limiting के लिए?
Answer
Custom view decorators wrap view functions to add cross-cutting concerns like authentication, request logging, rate limiting, and response modification without duplicating code.
// Custom Auth Decorator
from functools import wraps
from django.http import JsonResponse
from django.contrib.auth.decorators import login_required
def admin_only(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
if not request.user.is_staff:
return JsonResponse({"error": "Admin access required"}, status=403)
return func(request, *args, **kwargs)
return wrapper
@admin_only
def delete_user(request, user_id):
User.objects.get(id=user_id).delete()
return JsonResponse({"status": "deleted"})
// Custom Logging Decorator
import logging
from functools import wraps
logger = logging.getLogger(__name__)
def log_request(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
logger.info(f"User {request.user} accessing {func.__name__}")
logger.info(f"Method: {request.method}, Path: {request.path}")
try:
response = func(request, *args, **kwargs)
logger.info(f"Response status: {response.status_code}")
return response
except Exception as e:
logger.error(f"Error in {func.__name__}: {str(e)}", exc_info=True)
raise
return wrapper
@log_request
def dashboard(request):
return render(request, "dashboard.html")
// Rate Limiting Decorator
from functools import wraps
from django.core.cache import cache
from django.http import JsonResponse
def rate_limit(calls_per_minute=60):
def decorator(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
cache_key = f"ratelimit_{request.user.id}_{func.__name__}"
request_count = cache.get(cache_key, 0)
if request_count >= calls_per_minute:
return JsonResponse(
{"error": "Rate limit exceeded"},
status=429
)
cache.set(cache_key, request_count + 1, 60) # 60 seconds
return func(request, *args, **kwargs)
return wrapper
return decorator
@rate_limit(calls_per_minute=100)
def api_endpoint(request):
return JsonResponse({"data": [...]})
// Combined Decorators
from django.contrib.auth.decorators import login_required
@login_required
@rate_limit(calls_per_minute=200)
@log_request
def protected_api(request):
return JsonResponse({"data": "sensitive"})
// EXECUTION ORDER:
// 1. Check authentication
// 2. Check rate limit
// 3. Log request
// 4. Execute view
// Decorator with Arguments
def require_role(role):
def decorator(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
if not hasattr(request.user, "profile") or request.user.profile.role != role:
return JsonResponse({"error": "Insufficient permissions"}, status=403)
return func(request, *args, **kwargs)
return wrapper
return decorator
@require_role("editor")
def publish_article(request, article_id):
article = Article.objects.get(id=article_id)
article.published = True
article.save()
return JsonResponse({"status": "published"})
// Deprecation Warning Decorator
import warnings
from functools import wraps
def deprecated(replacement=None):
def decorator(func):
@wraps(func)
def wrapper(*args, **kwargs):
msg = f"{func.__name__} is deprecated"
if replacement:
msg += f". Use {replacement} instead"
warnings.warn(msg, DeprecationWarning, stacklevel=2)
return func(*args, **kwargs)
return wrapper
return decorator
@deprecated(replacement="new_api_endpoint")
def old_api_endpoint(request):
return JsonResponse({"data": []})Custom decorators views को wrap करके authentication, logging, rate limiting add करते हैं।
// Auth Decorator
def admin_only(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
if not request.user.is_staff:
return JsonResponse({"error": "Admin required"}, status=403)
return func(request, *args, **kwargs)
return wrapper
// Rate Limiting
def rate_limit(calls_per_minute=60):
def decorator(func):
@wraps(func)
def wrapper(request, *args, **kwargs):
cache_key = f"ratelimit_{request.user.id}"
count = cache.get(cache_key, 0)
if count >= calls_per_minute:
return JsonResponse({"error": "Rate limit"}, status=429)
cache.set(cache_key, count + 1, 60)
return func(request, *args, **kwargs)
return wrapper
return decorator
@admin_only
@rate_limit(100)
def api_view(request):
return JsonResponse({"data": []})Was this answer clear?