How to Use and Create Signals in Django?

Published On: 25/03/2025 | Category: Django
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 Project
django-admin startproject example
Step 2: Create a App
python3 manage.py startapp core
Step 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 migrate
Step 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.py
from django.apps import AppConfig

class CoreConfig(AppConfig):
name = 'core'

def ready(self):
    import core.signals
Django User Profile Created from Signal

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!