Here’s the scenario: You’re working on a project that will allow users to create an account and you’d like to save additional information about the user so you’ve created a “Profile” model. In order for everything to run smoothly each user needs to have a profile associated with their “User” model so you need a way to add this profile each time a new user creates an account. A super common scenario, right? Let’s start by taking a look at the models file as this is generally where I begin planning out projects anyway.
As you can see, each Profile is connected by a “ForeignKey” to a User model so that we can access the correct Profile information each time this user signs in the future. Now, once the user is registered we may take them directly to a profile page that displays their information or allows them to update information so we will need to access this new “Profile” model data immediately. If no profile has been created we’ll run into errors right away! One way to take care of this would be to create and save a new Profile each time a user registers for a new account. Let’s look at an example of this in our Views.py file.
This method of creating a new user and then creating a new profile for that user works just fine. It would appear that each time a new user account is created a new profile is also created. Recently I was working on a project and had a similar setup for creating new user accounts but kept running into errors when attempting to sign in as certain test users. That’s when I found out that others on the project with less programming experience had been creating new Users through Django’s built-in admin. Since this never hit the registration endpoint a Profile was never actually created for these users. Instead of requiring everyone to create users in a specific way, I incorporated Django signals!
Django signals are built-in utilities that allow us to run a block of logic any time that a specific event happens with a model. Django has 3 types of signals available for us:
Let’s see how we can use the post_save signal to fix the issue that I described above.
First, let’s create a new file within the app that our Profile model is in called signals.py and write the following code within this file.
What this does is creates a function called “create_project” that will be triggered after a new User is saved. If the user was just created it will create a new “Profile” model that is associated with the User model that triggered the function.
If we run our code right now, though, nothing will happen. In order to trigger “create_project” we need to add a little bit of code to the app.py file within the same application to tell it to listen for this signal.
By adding the bottom two lines we are connecting our signals file with our app file so that the signals will be triggered when we need them.
Now we need to change our view so that we are not creating 2 profiles each time! Here is an example of how the view can look now that our signal takes care of creating a new Profile each time a new User is created.
If you run this code now you will see that a Profile is created by our new signal. As an added bonus this can help us keep the rest of our code DRY which was briefly discussed in my last article (Context Processors Within Django). Maybe a User can sign up for a new account from multiple places throughout the project. Instead of having to remember to include the logic for creating a new Profile each time the signal will take care of this task. There are plenty of other applications for Django Signals. For instance, signals can help you avoid reusing code throughout your project, make an API call to delete user information from a third-party API after deleting a model, or avoid circular imports when overriding the model’s save method.
What are some ways you’ve used Django Signals or how do you think you can use them now that you’ve learned about them?