Subjects

All subjects Django Java Python React Spring Boot JavaScript PHP
Sign Up Free
Question 9 of 10 · Django Signals & Decorators
Interview question

What are performance considerations when using decorators and signals in Django? Django में decorators और signals use करते समय performance considerations क्या हैं?

Answer

Both decorators and signals add overhead. Minimize expensive operations in decorators, use caching strategically, and profile your code to identify bottlenecks. Async operations prevent request blocking.

IssueImpactSolution
Heavy decorator logicSlows response timeCache results, defer heavy work
Multiple decoratorsEach adds overheadCombine related logic
Synchronous signalsBlocks requestUse Celery for async
N+1 queries in signalsDatabase strainUse select_related
// ❌ SLOW - Heavy decorator
def check_permission_decorator(func):
    def wrapper(request, *args, **kwargs):
        # This runs on EVERY request
        all_permissions = Permission.objects.all()  # Heavy query
        allowed_perms = set(p.id for p in all_permissions)
        
        if request.user.id not in allowed_perms:
            return JsonResponse({"error": "No access"}, status=403)
        return func(request, *args, **kwargs)
    return wrapper

// ✅ FAST - Cached decorator
from django.core.cache import cache

def check_permission_decorator_cached(func):
    def wrapper(request, *args, **kwargs):
        cache_key = f"perms_{request.user.id}"
        permissions = cache.get(cache_key)
        
        if permissions is None:
            permissions = set(
                request.user.groups.values_list("permissions__id", flat=True)
            )
            cache.set(cache_key, permissions, 3600)
        
        if not permissions:
            return JsonResponse({"error": "No access"}, status=403)
        return func(request, *args, **kwargs)
    return wrapper

// Performance Testing
import time
from django.test import TestCase

class DecoratorPerformanceTest(TestCase):
    def test_decorator_overhead(self):
        def slow_decorator(func):
            def wrapper(*args, **kwargs):
                time.sleep(0.1)  # Simulates 100ms overhead
                return func(*args, **kwargs)
            return wrapper
        
        @slow_decorator
        def view(request):
            return JsonResponse({"data": "response"})
        
        start = time.time()
        for _ in range(100):
            view(MagicMock())
        total = time.time() - start
        
        print(f"100 requests: {total}s (10s overhead from decorator)")

// ❌ SLOW - Signal with N+1 queries
@receiver(post_save, sender=Book)
def update_categories(sender, instance, **kwargs):
    # N+1 problem: queries all related categories
    for category in Category.objects.all():
        category.book_count = category.books.count()
        category.save()

// ✅ FAST - Optimized signal
@receiver(post_save, sender=Book)
def update_category_optimized(sender, instance, **kwargs):
    # Only update related category
    if instance.category:
        instance.category.book_count = instance.category.books.count()
        instance.category.save()

// Profile Decorators
from django.test.utils import override_settings
import cProfile
import pstats

@override_settings(DEBUG=True)
def profile_view():
    pr = cProfile.Profile()
    pr.enable()
    
    # Run expensive view
    expensive_view(MagicMock())
    
    pr.disable()
    ps = pstats.Stats(pr)
    ps.print_stats()  # Shows where time is spent

// Minimize Decorator Stack
# ❌ Multiple decorators per view
@decorator1
@decorator2
@decorator3
@decorator4
@expensive_decorator
def view1(request):
    pass

# ✅ Combine related decorators
def combined_auth_and_logging(func):
    def wrapper(request, *args, **kwargs):
        # Do both auth and logging efficiently
        logger.info(f"Request from {request.user}")
        if not request.user.is_authenticated:
            return redirect("login")
        return func(request, *args, **kwargs)
    return wrapper

@combined_auth_and_logging
def view2(request):
    pass

Decorators और signals overhead add करते हैं। Heavy operations को defer करो, caching use करो, async use करो।

IssueImpactSolution
Heavy decoratorSlow responseCache, defer work
Sync signalsBlocks requestUse Celery
N+1 queriesDB strainOptimize queries
// ❌ Slow
@decorator_with_heavy_query
def view(request):
    pass

// ✅ Fast
@cached_permission_decorator
def view(request):
    pass

// Use Celery for heavy signals
@receiver(post_save, sender=Book)
def trigger_async(sender, instance, **kwargs):
    process_async.delay(instance.id)

Was this answer clear?