📡

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

  1. Implicit execution — no explicit call in code, so "who's calling this?"
  2. Order not guaranteed — receiver order depends on registration but isn't guaranteed
  3. Transaction issues — post_save may fire before transaction commit. Use transaction.on_commit()
  4. 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)

References