Interview question
What are best practices for using Django Signals? What are common pitfalls? Django Signals use करने की best practices क्या हैं? Common pitfalls क्या हैं?
Answer
Signals are powerful but can cause confusion and performance issues if misused. Follow best practices to avoid circular imports, performance problems, and debugging difficulties.
| Best Practice | Why |
|---|---|
| Define signals in signals.py | Organized, avoid circular imports |
| Import in apps.py ready() | Executed once at startup |
| Keep signal handlers lightweight | They block request processing |
| Use @receiver decorator | Cleaner, more readable code |
| Avoid heavy queries | Each save triggers query |
| Use dispatch_uid | Prevent duplicate signal connections |
// ✅ CORRECT - signals.py with apps.py
// myapp/signals.py
from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Book
@receiver(post_save, sender=Book)
def update_cache(sender, instance, created, **kwargs):
# Keep this lightweight
cache.set(f"book_{instance.id}", instance)
// myapp/apps.py
from django.apps import AppConfig
class MyAppConfig(AppConfig):
name = "myapp"
def ready(self):
import myapp.signals # Import signals
// ❌ WRONG - Signal in models.py (circular import risk)
// models.py - DON't do this!
from django.db.models.signals import post_save
@receiver(post_save, sender=Book)
def update_cache(sender, instance, **kwargs):
pass # Causes circular import issues
// Using dispatch_uid
@receiver(post_save, sender=Book, dispatch_uid="update_book_cache")
def update_cache(sender, instance, **kwargs):
# dispatch_uid prevents duplicate connections
pass
// ✅ Best: Async heavy operations
from celery import shared_task
@receiver(post_save, sender=Book)
def trigger_email(sender, instance, created, **kwargs):
if created:
send_email_async.delay(instance.id)
@shared_task
def send_email_async(book_id):
book = Book.objects.get(id=book_id)
send_notification_email(book)
// ❌ AVOID: Heavy queries in signals
@receiver(post_save, sender=Book)
def bad_handler(sender, instance, **kwargs):
# Bad: This will be called for EVERY save
all_books = Book.objects.all() # Heavy query
for book in all_books:
book.update_something()
// ✅ CORRECT: Use select_related to optimize
@receiver(post_save, sender=Book)
def good_handler(sender, instance, **kwargs):
# Only update related object
instance.category.update_book_count()
// ✅ CORRECT: Disconnect signals in tests
from django.db.models.signals import post_save
from django.test import TestCase
class BookTestCase(TestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
post_save.disconnect(update_cache, sender=Book)
@classmethod
def tearDownClass(cls):
super().tearDownClass()
post_save.connect(update_cache, sender=Book)Signals powerful हैं लेकिन अगर गलत तरीके से use करें तो समस्याएं हो सकती हैं।
| Best Practice | क्यों |
|---|---|
| signals.py में define करो | Organized, imports safe |
| apps.py में import करो | Circular imports avoid |
| Lightweight handlers | Request block नहीं हो |
| Async भारी operations | Performance improve |
// signals.py में define करो
from django.db.models.signals import post_save
from django.dispatch import receiver
@receiver(post_save, sender=Book, dispatch_uid="update_cache")
def update_cache(sender, instance, **kwargs):
cache.set(f"book_{instance.id}", instance)
// apps.py में import करो
class MyAppConfig(AppConfig):
def ready(self):
import myapp.signalsWas this answer clear?