What is Signal?

We are familiar with signals & we see much usage of different types of signals. Suppose your friends and you are having fun in your classroom. You assigned one of your friends as an informer who will give you a signal if he sees a teacher coming.

In programming, signals are callables which are called before/after an event.

Signals in Django

Signals in django establishes information among applications. They send information based on any events which is occurred or is going to be occurred. After sender sends the signal, the receiver function receives that signal. We use @receiver decorator for making a receiver function for which we need to execute when specific signal is called.

Arguments of django signals.

Most of the Django’s signals sends 2 arguments to the receivers. They are:

  • Sender: The model class which is sending the signals.
  • Instance: The actual instance of the model that is being modified (Create, Update or Delete)

Django Built-In Signals

Django has a lot of built-in signals. Like model and request/response signals. We can also write our own signals using Signal class.

from django.dispatch.dispatcher import Signal

This Signal class is the Base class for all django signals.

Model Signals

django.db.models.signals.pre_save 

pre_save acts before calling a model’s save() method.

django.db.models.signals.post_save

post_save acts after calling a model’s save() method.

django.db.models.signals.pre_delete 

pre_delete acts before calling a model’s delete() or queryset’s delete() method.

django.db.models.signals.post_delete

post_delete acts after a model’s delete() method or queryset’s delete() method is called.

django.db.models.signals.pre_init

This signal works before instantiating a model’s (__init__() method)

django.db.models.signals.post_init

This signal works after instantiating a model’s (__init__() method)

django.db.models.signals.m2m_changed

m2m_changed‘ acts on ManyToManyField field.

There are more signals in django.

Request / Response Signals

django.core.signals.request_started

Sent when Django starts an HTTP request.

django.core.signals.request_finished

Sent when Django finishes an HTTP request.

Example

In every social media application, each user has a profile. User needs to give some required information (like first_name, last_name, email) during registration & other additional information (like bio, profile image, education, phone_no) can be updated later. So, there must be a mechanism for creating a Profile object with the creation of each User object. We have two models ‘Person’ & ‘PersonsProfile’. When we will create a ‘Person’ object a ‘PersonsProfile’ object will have to be created automatically.

We will do this job using a signal.

Our Models:

class Person(models.Model):
    GENDER = (
        ('Male', 'Male'),
        ('Female', 'Female'),
    )
    first_name = models.CharField(max_length=30)
    last_name = models.CharField(max_length=30)
    email = models.EmailField(unique = True,null=True)
    gender = models.CharField(max_length=6, choices= GENDER, default='N/A')

    class Meta:
        verbose_name_plural = 'All Persons'

    @property
    def full_name(self):
        return f'{self.first_name} {self.last_name}'

    def __str__(self):
        return f'{self.first_name} {self.last_name}'
    

class PersonsProfile(models.Model):
    user= models.OneToOneField(Person,on_delete=models.CASCADE)
    bio = models.CharField(max_length=100,null=True,blank=True)
    phone_no = models.PositiveIntegerField(unique=True,null=True)

    @property
    def username(self):
        return self.user.full_name

    def __str__(self):
        return self.user.full_name

Let’s create a signals.py file inside our app directory and add this code snippet:

signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Person, PersonsProfile


@receiver(post_save, sender=Person)
def create_profile(sender, instance, created, **kwargs):

    if created:
        PersonsProfile.objects.create(user=instance)
        post_save.connect(create_profile, sender=Person)

Along with the sender & instance arguments, post_save signal sends another useful argument called created which is useful to understand if the object is being created or updated. If the object is created the value is True & if not created or updated the value will be False. We can send additional keyword arguments in **kwargs.

For better understanding you can check the value & type of the arguments with the help of print() function.

Now, in apps.py file we will add the ‘ready()’ method. This method will register our ‘signal’ in the app.

apps.py

from django.apps import AppConfig

class FirstAppConfig(AppConfig):
    name = 'first_app'

    def ready(self):
        import first_app.signals 

Inside our __init__.py we will define our default application config to ‘FirstAppConfig’. It must be a string.

default_app_config = 'first_app.apps.FirstAppConfig'

We are all set. Now we will run the server and create an object of ‘Person’ model.

After saving the ‘Person’ object we will see an automatically created object in ‘PersonsProfile’ table.

This was a simple example. I hope you have gotten a clean & clear understanding of signals. Now try to play with other signals.

+ posts

Author | Python-Django Developer

+ posts

Full-stack Developer (Python | Django | React | React-Native | Angular | Vue)