Django signals allow one part of the app (sender) to send notifications without knowing which parts (receivers) will respond. This means components don't need to import or call each other directly, keeping them independent and easier to maintain.
When a Django signal is sent, all receivers connected to that signal are called automatically in the order they were connected. The sender does not need to know or call them explicitly, which supports decoupling.
Connecting signal receivers inside the ready() method of AppConfig ensures they are registered once the app is fully loaded. This avoids import side effects and ensures signals work reliably.
from django.db.models.signals import post_save from django.dispatch import receiver from .models import Book @receiver(post_save, sender=Book) def book_saved(sender, instance, created, **kwargs): print('Book saved!')
The @receiver decorator with post_save and sender=Book correctly connects the function. The function signature must include sender, instance, created, and **kwargs to match the signal's parameters.
When connecting a signal without specifying sender, the receiver listens to all models' post_save signals. This can cause unexpected behavior or missed triggers if the sender is not filtered. Specifying sender=User ensures the receiver only listens for User model saves.