Open In App

How to Create and Use Signals in Django ?

Improve
Improve
Like Article
Like
Save
Share
Report

In this article, we’ll dive into the powerful world of Django signals, exploring how to create and use them effectively to streamline communication and event handling in your web applications.

Signals in Django

Signals are used to perform any action on modification of a model instance. The signals are utilities that help us to connect events with actions. We can develop a function that will run when a signal calls it. In other words, Signals are used to perform some action on the modification/creation of a particular entry in the Database. For example, One would want to create a profile instance, as soon as a new user instance is created in Database

There are 3 types of signals:

  1. pre_save/post_save: This signal works before/after the method save().
  2. pre_delete/post_delete: This signal works before after deleting a model’s instance (method delete()) this signal is thrown.
  3. pre_init/post_init: This signal is thrown before/after instantiating a model (__init__() method).

    Refer to the following articles to check how to create a project and an app in Django.

       How to Create a Basic Project using MVT in Django?

       How to Create an App in Django ?

How to use Signals in Django?

For example, if we want to create a profile of a user as soon as the user is created using post_save signal

Models.py: This code defines a Django model called “Profile” with two fields: “user” and “image”. It establishes a one-to-one relationship with the built-in User model, and the “image” field stores user profile pictures in the “profile_pics” directory with a default image named “default.jpg.” The __str__ method returns a string representation of the user’s profile by using their username.

Python3




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'


views.py: This code is a part of a Django web application. It defines two view functions:

  • register: This function handles user registration. It checks if the HTTP request method is POST, validates a user registration form, creates a new user account, and then redirects to the login page if the registration is successful.
  • profile: This function is a protected route that requires users to be logged in. It allows users to update their profile information. It handles both GET and POST requests, rendering a profile update form and processing the form data if the request method is POST. If the form data is valid, it updates the user’s information and redirects back to the profile page with a success message.

Python3




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 are now able to 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 account 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)


forms.py: This Python code defines three Django forms for user registration and profile updates. UserRegisterForm extends UserCreationForm and adds an email field, while UserUpdateForm and ProfileUpdateForm allow users to update their username, email, and profile image information. These forms are designed to interact with Django’s authentication system and user profiles.

Python3




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']


signals.py(Using receiver method): This code is part of a Django project and sets up signal handlers for the User model. When a new User instance is created, it automatically creates a corresponding Profile instance (create_profile function) and saves it (save_profile function). These signals are triggered when a User model is saved or deleted.

Python3




# code
from django.db.models.signals import post_save, pre_delete
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()


You can get confused from this piece of code if you are new to Django, So what is happening is when the User model is saved, a signal is fired called create_profile which creates a Profile instance with a foreign key pointing to the instance of the user. The other method save_profile just saves the instance.

Now let’s understand the arguments 

  • receiver – The function who receives the signal and does something.
  • sender – Sends the signal
  • created — Checks whether the model is created or not
  • instance — created model instance
  • **kwargs –wildcard keyword arguments

Another way to connect the signal with the function:

You need to connect the signals file with the app.py file ready function in order to use them. 

Python3




from django.apps import AppConfig
 
class UsersConfig(AppConfig):
    name = 'users'
 
    def ready(self):
        import users.signals


Here the signal lives. 

If we create a user 

Then his profile is automatically created.

You can check it in admin view too 

Using Receiver Method using pre_save

pre_save: Pre_save method is provoked just before the save function is called, Also the model is saved only after successful execution of pre_save method 

Python3




# code
from django.db.models.signals import post_save, pre_delete,pre_save
from django.contrib.auth.models import User
from django.dispatch import receiver
from .models import Profile
 
 
@receiver(pre_save, sender=User)
def checker(sender, instance, **kwargs):
    if instance.id is None:
        pass
    else:
      current=instance
      previous=User.objects.get(id=instance.id)
      if previous.reaction!= current.reaction:
               #save method can be called


We use this if  reaction is changed.

Using signals Connect Method

The alternative way of above method is to use connect method to fire signals.

If you just use post_save.connect(my_function), then it will get fired as soon as any save method is fired.

post_save.connect(my_function_post_save, sender=MyModel)
pre_save.connect(my_function, sender= UserTextMessage)


Last Updated : 06 Nov, 2023
Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads