Connecting Signals to Receivers
In this page:
Two Ways to Connect a Receiver
You can connect a receiver with the @receiver decorator, or by calling signal.connect(func, sender=Model) directly — both do the same thing.
Example: Two Ways to Connect a Receiver
You can connect a receiver with the @receiver decorator, or by calling signal.connect(func, sender=Model) directly — both do the same thing.
from django.dispatch import receiver
from django.db.models.signals import post_delete
from .models import Comment
@receiver(post_delete, sender=Comment)
def log_delete(sender, instance, **kwargs):
print(f"Comment {instance.pk} deleted")
# Equivalent without the decorator:
# post_delete.connect(log_delete, sender=Comment)
{# Django-only code -- models.py/views.py/urls.py/settings.py
snippets, or template markup using Django template tags/variables
-- can't run standalone via Judge0 or the browser preview, since
it needs a real Django project. Only this course's pure-Python
examples (example_lang == 'python', no Django imports) are
actually runnable, so those still get the button below. #}
Making Sure Receivers Get Registered
A receiver only works if Python actually imports the module it's defined in. The standard place to do this is AppConfig.ready(), which Django calls once at startup.
Example: Making Sure Receivers Get Registered
A receiver only works if Python actually imports the module it's defined in. The standard place to do this is AppConfig.ready(), which Django calls once at startup.
from django.apps import AppConfig
class BlogConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "blog"
def ready(self):
import blog.signals
{# Django-only code -- models.py/views.py/urls.py/settings.py
snippets, or template markup using Django template tags/variables
-- can't run standalone via Judge0 or the browser preview, since
it needs a real Django project. Only this course's pure-Python
examples (example_lang == 'python', no Django imports) are
actually runnable, so those still get the button below. #}
Connecting the Same Receiver to Multiple Senders
One receiver function can be connected to more than one model, either by calling connect() several times or looping over a list of senders.
Example: Connecting the Same Receiver to Multiple Senders
One receiver function can be connected to more than one model, either by calling connect() several times or looping over a list of senders.
from django.db.models.signals import post_save
from .models import Article, Comment
def log_save(sender, instance, **kwargs):
print(f"{sender.__name__} saved")
for model in (Article, Comment):
post_save.connect(log_save, sender=model)
{# Django-only code -- models.py/views.py/urls.py/settings.py
snippets, or template markup using Django template tags/variables
-- can't run standalone via Judge0 or the browser preview, since
it needs a real Django project. Only this course's pure-Python
examples (example_lang == 'python', no Django imports) are
actually runnable, so those still get the button below. #}
Disconnecting a Receiver
Receivers can be removed with signal.disconnect(), which is mainly useful in tests where you want to temporarily silence a side effect.
Example: Disconnecting a Receiver
Receivers can be removed with signal.disconnect(), which is mainly useful in tests where you want to temporarily silence a side effect.
from django.db.models.signals import post_save
from .signals import log_save
from .models import Article
post_save.disconnect(log_save, sender=Article)
{# Django-only code -- models.py/views.py/urls.py/settings.py
snippets, or template markup using Django template tags/variables
-- can't run standalone via Judge0 or the browser preview, since
it needs a real Django project. Only this course's pure-Python
examples (example_lang == 'python', no Django imports) are
actually runnable, so those still get the button below. #}
- Defining a receiver function but never connecting it, or connecting it in a module that's never imported.
- Connecting signals inside a model's save() method, which reconnects the same receiver on every save.
- Not using sender= to scope the receiver, causing it to run for every model in the project.
- A receiver is just a normal Python function with a matching signature.
- Use @receiver(signal, sender=Model) or signal.connect(func, sender=Model) to connect it.
- Signal receivers must be imported somewhere for Django to actually register them, usually via AppConfig.ready().
- Scope receivers to a specific sender to avoid unexpected side effects on unrelated models.
Chapter Quiz — Complete all 8 topics to unlock
0/8 topics done
Complete these topics first: