📡
Django Signals — Event-Based Loose Coupling
How post_save and pre_delete work internally
Internal Implementation
django.dispatch.Signal has a receivers list internally. connect() registers functions, send() calls all registered functions sequentially.
post_save.send() is called inside Model.save().
Why Be Careful
- Implicit execution — no explicit call in code, so "who's calling this?"
- Order not guaranteed — receiver order depends on registration but isn't guaranteed
- Transaction issues — post_save may fire before transaction commit. Use
transaction.on_commit() - Test complexity — Signals fire in tests too, causing unexpected side effects
Alternative: explicit service function calls are more traceable. Signals only for cross-app loose coupling.
Key Points
1
Register receiver functions with Signal.connect()
2
Model.save() calls post_save.send() internally → all registered receivers execute
3
Receivers receive sender, instance, created, etc. as arguments
4
For transaction safety, handle inside transaction.on_commit()
Use Cases
Auto-create profile on user creation
Send notification on order completion (cross-app loose coupling)