How to Use and Create Signals in Django?

Published On: 10/09/2022 | Category: Django


Hi Dev,

In this example, you will learn how to use and create signals in django. you will learn how to create and use signals in django. We will look at example of how to use signals in django. This article will give you simple example of django custom signals example. Let's get started with custom signals in django.

The 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. Signals are utilized to perform some action on modification/creation of a particular entry in 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 signal:
  • pre_save/post_save: This signal works before/after the method save().
  • pre_delete/post_delete: This signal works before after delete a model’s instance (method delete()) this signal is thrown.
  • pre_init/post_init: This signal is thrown before/after instantiating a model (__init__() method).

So,How to use Signals ion Django: Signals is basically use to if we want to create a profile of a user as soon as the user is created using post_save signal

Here i explained simply step by step example of how to use and create signals in django.

Step 1: Create a Project

In this step, we’ll create a new django project using the django-admin. Head back to your command-line interface and run the following command:

django-admin startproject example
Step 2: Create a App

Now we'll create a single app called core to store a list of post names. We're keeping things intentionally basic. Stop the local server with Control+c and use the startapp command to create this new app.

python3 manage.py startapp core
Step 3: Update setting.py

Then update INSTALLED_APPS within our settings.py file to notify Django about the app.

settings.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

Now go for the models we will We'll call our single model Post and it will have just two fields: user and image. And finally set __str__ to display the username of the user in admin interface.

core/models.py
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'

Ok, all set. We can engender a migrations file for this change, then integrate it to our database via migrate.

python manage.py makemigrations
python manage.py migrate
Step 5: Create a Form

In this step We need to create a form that will be used .like add a UserCreationForm in contrib.auth.forms,second form is UserUpdateForm and last one is ProfileUpdateForm. and plus we need to add custom styling.

core/forms.py
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

In this step, we need to configure our five views. The register page will be a register template with UserRegisterForm in django template. profile view is update the user profile using UserUpdateForm and ProfileUpdateForm open the core/views.py file and add:

core/views.py
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)
Step 7: Creating the signals.py File

In this step, we need to configure a signals.py. The create_profile method is Using receiver method profile is create open the core/views.py file and add:

core/signals.py
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()

Here, You can get confused from this some 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.

  • 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.

We need to connect the signals file with the apps.py file ready function in order to use them.

core/apps.py
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:



pre_save using Receiver Method:

this 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

# 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

Next, we can using signals Connect Method

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

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

I hope it will help you....

Happy Coding!