Django Signals Explained with a Practical Example

 

Django Signals are a way to run code automatically when something happens in the application.

 

To test quickly: Create a simple Django project or clone mysite, a basic Django project from my GitHub:

git clone https://github.com/38130/mysite

Throughout this post, assume the following project structure:

mysite/
mysite/
settings.py
urls.py
polls/
apps.py
models.py
signals.py
views.py
urls.py
manage.py

 

What are signals?
 

A signal is a notification sent by Django when something happens. Pay attention to a signal based on the creation of a new user:

User is created
  ↓
Django sends a signal
  ↓
A function receives the signal
  ↓
Extra code runs automatically


Simple idea:
A signal lets one part of Django react to something that happened somewhere else.

 

 

Using post_save
 

The post_save signal runs after an object is saved. A practical example is reacting when a new user is created.

Imagine that whenever someone creates a new account, we want to notify someone by email. We will only use print("Send email").

Inside the polls app, create a file called signals.py.

from django.db.models.signals import post_save
from django.dispatch import receiver
from django.contrib.auth.models import User


@receiver(post_save, sender=User)
def user_created(sender, instance, created, **kwargs):
    if created:
        print(f"New user created: {instance.username}")
        print("Send email")

If an existing user is updated, the signal still runs, but created will be False.

 

Common uses for post_save:

  • Create related objects automatically
  • Send notifications
  • Write logs
  • Trigger background tasks

 

 

Loading signals
 

Creating signals.py is not enough. Django needs to import that file when the app starts.

from django.apps import AppConfig


class PollsConfig(AppConfig):
    default_auto_field = "django.db.models.BigAutoField"
    name = "polls"

    def ready(self):
        import polls.signals

The ready() method runs when Django loads the app.

By importing polls.signals there, we make sure the signal receivers are registered.

 

 

 

 

Simple idea:
Use signals for automatic side effects.
Avoid hiding important business logic in signals.

 

 

 

In short:

Signals let Django react automatically to events.
They are useful for side effects such as emails, logs, notifications, cache updates or cleanup.
Use them carefully, because hidden logic can become hard to follow.

 

 

 

Other signals
 

There are more signals in Django, but these are some useful examples:

Model signals

  • pre_save — before saving an object
  • post_save — after saving an object
  • pre_delete — before deleting an object
  • post_delete — after deleting an object
  • m2m_changed — when a ManyToManyField changes

Authentication signals

  • user_logged_in — after a user logs in
  • user_logged_out — after a user logs out
  • user_login_failed — when a login attempt fails

Request signals

  • request_started — when Django starts handling a request
  • request_finished — when Django finishes handling a request
  • got_request_exception — when an exception happens while handling a request