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 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).
Refer to the following articles to check how to create a project and an app in Django.
How to use Signals ion 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
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
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
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)
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
pre_save using Receiver Method –
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)