Signal-based decoupling
Table of contents
Introduction
Features announce business events through blinker signals. The feature that sends one does not know who listens, so you add or remove a listener without touching it.
# splent_feature_reports/signals.py
from splent_framework.signals.signal_utils import connect_signal
@connect_signal("note-created", "splent_feature_reports")
def on_note_created(sender, note, **kwargs):
... # count the note in today's report
When somebody writes a note, reports counts it, and notes never imports reports.
Defining and sending a signal
# splent_feature_notes/signals.py
from splent_framework.signals.signal_utils import define_signal
note_created = define_signal("note-created", "splent_feature_notes")
# splent_feature_notes/services.py
note_created.send(current_app._get_current_object(), note=note)
Signal names use hyphens, and feature:contract lists them under provides.signals.
Listening to a signal
Connect in your feature’s own signals.py, by name, as the introduction shows. A handler whose sender has not loaded yet is connected when its define_signal runs, so load order does not matter. If the sender is not installed, the handler never fires.
Signals or template hooks
| Mechanism | Layer | Use it to |
|---|---|---|
| Signals | Business logic | React to domain events, such as an order placed |
| Template hooks | Presentation | Put HTML into another feature’s templates |
See also
- Signals, the API reference