How to Use and Create Signals in Django?

Hi Dev,
In this comprehensive tutorial, you will learn how to use and create signals in Django. We'll explore how to automatically trigger actions like creating a profile when a new user is registered, using built-in signals like post_save
, pre_save
, and more.
This article gives you a complete guide with a working example of Django custom signals, including models, forms, views, and signals. Let's get started with Django signals step-by-step.
Django signals are used to perform actions after or before a model’s instance is saved or deleted. For example, creating a user profile immediately after a user is registered.
Types of Django Signals:
- pre_save/post_save: Triggered before/after
save()
method is called. - pre_delete/post_delete: Triggered before/after
delete()
method is called. - pre_init/post_init: Triggered before/after the model’s
__init__()
constructor is run.
We’ll now walk through a real-world example using the post_save signal to automatically create a user profile.
Step 1: Create a Projectdjango-admin startproject exampleStep 2: Create a App
python3 manage.py startapp coreStep 3: Update setting.py
.... INSTALLED_APPS = [ 'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'core', ]Step 4: Create a Model
from django.db import models from django.contrib.auth.models import User from PIL import Image class Profile(models.Model): user = models.OneToOneField(User, on_delete=models.CASCADE) image = models.ImageField(default='default.jpg', upload_to='profile_pics') def __str__(self): return f'{self.user.username} Profile'
python manage.py makemigrations python manage.py migrateStep 5: Create a Form
from django import forms from django.contrib.auth.models import User from django.contrib.auth.forms import UserCreationForm from .models import Profile class UserRegisterForm(UserCreationForm): email = forms.EmailField() class Meta: model = User fields = ['username', 'email', 'password1', 'password2'] class UserUpdateForm(forms.ModelForm): email = forms.EmailField() class Meta: model = User fields = ['username', 'email'] class ProfileUpdateForm(forms.ModelForm): class Meta: model = Profile fields = ['image']Step 6: Creating the Views
from django.shortcuts import render, redirect from django.contrib import messages from django.contrib.auth.decorators import login_required from .forms import UserRegisterForm, UserUpdateForm, ProfileUpdateForm def register(request): if request.method == 'POST': form = UserRegisterForm(request.POST) if form.is_valid(): form.save() username = form.cleaned_data.get('username') messages.success(request, f'Your account has been created! You can now log in.') return redirect('login') else: form = UserRegisterForm() return render(request, 'users/register.html', {'form': form}) @login_required def profile(request): if request.method == 'POST': u_form = UserUpdateForm(request.POST, instance=request.user) p_form = ProfileUpdateForm(request.POST, request.FILES, instance=request.user.profile) if u_form.is_valid() and p_form.is_valid(): u_form.save() p_form.save() messages.success(request, f'Your profile has been updated!') return redirect('profile') else: u_form = UserUpdateForm(instance=request.user) p_form = ProfileUpdateForm(instance=request.user.profile) context = { 'u_form': u_form, 'p_form': p_form } return render(request, 'users/profile.html', context)Step 7: Creating the signals.py File
from django.db.models.signals import post_save from django.contrib.auth.models import User from django.dispatch import receiver from .models import Profile @receiver(post_save, sender=User) def create_profile(sender, instance, created, **kwargs): if created: Profile.objects.create(user=instance) @receiver(post_save, sender=User) def save_profile(sender, instance, **kwargs): instance.profile.save()
This ensures that a Profile is automatically created whenever a new User is added to the system.
core/apps.pyfrom django.apps import AppConfig class CoreConfig(AppConfig): name = 'core' def ready(self): import core.signals

pre_save Example:
@receiver(pre_save, sender=User) def checker(sender, instance, **kwargs): if instance.id: current = instance previous = User.objects.get(id=instance.id) if previous.reaction != current.reaction: # save method will continue
Connecting Signals Manually:
post_save.connect(my_function_post_save, sender=MyModel) pre_save.connect(my_function, sender=User)
FAQs - Django Signals
Q1: What are signals used for in Django?
A: Signals allow decoupled applications to get notified when actions occur elsewhere in the framework.
Q2: When should I use post_save signal?
A: Use post_save when you need to perform an action right after a model instance is saved, like creating a related profile.
Q3: Can signals slow down performance?
A: Yes, heavy logic inside signals can affect performance. Keep them light or move logic to async tasks.
Q4: How do I ensure signals run automatically?
A: Make sure you import your signals module in the apps.py
using the ready()
method.
Q5: Is it better to use signals or override model methods?
A: Use signals for decoupled logic. If behavior is tightly coupled with model, overriding methods is preferred.
I hope this guide helps you implement Django signals successfully in your project!
Happy Coding!