What are Django signals?

If you’ve checked out any of my previous posts, you know that I like to get nerdy about learning new things. I’m all about learning new skills, especially if they result in my projects being able to do more with writing less code. I’m all about efficiency. I’ve also been diving into the Django framework and everyday I’m starting to learn more and more about neat features that really utilize every feature of the framework. Today, we’re looking at Django signals.

Django signals are used when different pieces of code are used in the same event. They use a sender and a receiver to communicate about an action or event that taken place in the code. In essence, when one part of the code does something, it sends a signal to another part of the code, which will then do something else.

All signals have to be imported using:

from django.db.models.signals 

From here you can import the exact signals you want. For organization purposes it’s a good idea to create a ‘signals.py’ file in what ever app you want to utilize signals.

Some examples of popular signals are:

pre_save & post_save#used before and after a model's save() method are used. By looking at the syntax, you can easily figure out the sender and receiver parts.pre_delete & post_delete#used before and after a model's delete() method or a query's delete() method are used.m2m_changed#used when a model's ManyToManyField has been changedrequest_started & request_finished#used when Django starts and finishes an HTTP request

Now listing these out are one thing, but giving an example using them is much more helpful. Let’s take a look at a practical use for signals and show how I implemented them to help update a user’s profile. This will make use of the pre_save signal.

When building out a pre_save method, there are a number of required arguments:

sender: this is the model class. In this case, it’s User

instance: the actual instance of the class being used, in this case it’s an individual user profile

I’m also going to use **kwargs to take care of any other arguments that go with the User class. Check out my post here to learn more about **kwargs!

In using the signal, I want to update the user email to match the username. That’ll improve the user experience as they now only have to use their email to log in.

Imports go first:

from django.db.models.signals import pre_save
from django.contrib.auth.models import User #This code is in its own file, therefore I must import the user model.
def updateUser(sender, instance, **kwargs):
user = instance
if user.email != '':
user.username = user.email
pre_save.connect(updateUser, sender=User)

That connect() method at the bottom is what ties the User model to the signal. It also assigns the value of ‘sender’ to the User class.

A quick play-by-play to explain how this signal is working:

This signal is listening to when the updateUser method is being called. It’s going to focus on the instance of a User, and when that specific user gets updated.

It’s going to find the email field associated with that user and check to see if it’s NOT empty. Or checking to see if there actually is an email address. If there is an email provided with the user, the signal will update the username for that profile to match the email address. This means that each user only needs to remember their email address when logging in/out of the application. This small use of signals makes updating multiple fields of the user profile super simple!

This is just a small, but effective example of how to implement Django signals. They are incredibly helpful in a wide variety of uses to improve functionality in an application. To learn more, check out the official documentation here or watch a video of theme being implemented here.

Software Engineer in NYC with expertise in Ruby on Rails, JavaScript, and React