In this tutorial, we will know how to create signals in Django and its uses. Also, know about the type of signals. We will use the Django signals post_save and create a blog application that sends email notifications whenever a new blog post is created.
What are signals in Django?
Consider signals as a mechanism for various Django application components to communicate with one another without being aware of one another. Signals enable specific actions or events in your application to transmit a message, which other portions of your code can then receive and react to.
To understand it in simple words, suppose you have a home with many rooms, and you want to be aware of any entrances and exits. For that sensors can be installed at the doorways to send notifications anytime someone enters or exits. Signals operate in a similar manner in Django.
Similar to how walking through a doorway causes a notification to be sent, certain activities, such as storing or deleting an object, can cause a signal to be sent. Then other components of your code called signal receivers, can be configured to listen for those signals and take certain actions when they are triggered.
For example, a signal can be sent to inform other parts of the code that a new user has been created when a user registers on a website. This signal can trigger actions like sending a welcome email, the creation of a user profile or updating related data.
Now we know about signals, In Django, there are several types of signals that exist for different events. Here we will discuss some of the common signals.
- pre_save: Just before the save() method of a model is called, this signal is sent. Before Strogin the data in the database, it provides a mechanism to perform operations or modify the data.
- post_save: When the save() method for a model is successfully executed, this signal is sent. It enables you to take action once the data has been stored, such as updating related models, sending notifications, or starting other processes.
- pre_delete: Just before a model’ delete() method is called, this signal is sent. Before deleting an object from the database, it can be used to carry out actions and take safety measures.
- post_delete: After a model’s delete() method has been successfully executed, this signal is sent. It provides the chance to do actions once an object has been removed, such as clearing out associated ata or sending notifications.
- pre_init: Before the object is initialized, this signal is sent when a model’s constructor is called. Before the object is created, it can be helpful to make further setup or modification.
- post_init: When a mode’s constructor is finished, after the object has been initialized, this signal is sent. After the object is created, it enables you to carry out more operations or modifications on it.
- m2m_changed: This signal is issued when a many-to-many relationship is changed. It provides details about relationship modifications, such as the addition or deletion of associated objects.
- pre_migrate: Before migration is applied to the database, this signal is sent. It enables you to make changes or actions before the migration is carried out.
- post_migrate: After the migration has been applied to the database, this signal is sent. Once the migration has been successfully executed, it provides the chance to carry out actions or any modifications.
Next, we will create a blog application in Django that send email notification using signals whenever a new blog post is created.
Read How to Create a Chip with Filter in Django
Setting up the directory structure and virtual environment
First, open the terminal or command prompt and navigate to the desired location where you want to create your Django blog project.
Create a new directory for your project such as blogproject and move to that directory.
makdir blogproject
cd blogproject
Create a virtual environment for your blog project.
python -m venv benv
Activate the virtual environment that you have created.
To activate the virtual environment on Windows type the below command.
benv\Scripts\activate
To activate the virtual environment on macOS/Linux type the below command.
source benv/bin/activate
After activating the virtual environment, install Django using the below command.
pip install django
Now your project directory has been configured and Django has been installed.
Create a new Django project named “blogproj” using the django-admin command.
django-admin startproject blogproj .
The above command uses the current directory which is indicated by the dot(.) to create a new Django project called “blogproj”.
Navigate to its root directory and create a Django app called “blog” using the below commands.
python manage.py startapp blog
To view the files and folder of the current directory type the command.
dir
After creating the blog app, open the project in the visual studio by typing the below command.
code .
After opening the project in vs code, open the terminal and type the below command to set up the database for your blog project.
python manage.py migrate
Then verify that the project is set up correctly by running the development server using the below command.
python manage.py runserver
After copying the URL ( http://127.0.0.1:8000/ ), paste it into your browser and you will see the application running successfully.
Now update the “INSTALLED _APP” setting in the “setting.py” file to include the ‘blog’ application.
INSTALLED_APPS = [
......
'blog'
......
]
Next, create the Post model in the “blog/models.py” file using the following code.
Import the necessary libraries or modules.
from django.db import models
from django.db.models.signals import post_save
from django.dispatch import receiver
from django.core.mail import send_mail
Define the Post model using the below code.
class Post(models.Model):
title = models.CharField(max_length=100)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
Define a signal receiver function using the below code.
@receiver(post_save, sender = Post)
def send_notification(sender, instance, created, **kwargs):
if created:
subject = "New blog post created"
message = 'A new blog post "{}" has been created.'.format(instance.title)
send_mail(subject, message, 'iamtheks9004@gmail.com',['saurabhsingh9004@gmail.com'])
Let’s understand the signal receiver function and how to define this function. First, you need to know about “@receiver(post_save, sender = Post)”.
The “@receiver(post_save, sender = Post)” decorator is used to register the ‘send_notification’ function as a receiver for the ‘post_save’ signal emitted by the ‘Post’ model.
The syntax of the ‘@receiver’ decorator in Django is as follows:
@receiver(signal, sender = None)
def receiver_function(sender, **kwargs):
# Receiver function body
- @receiver: The @ sign is followed by the decorator’s name (in this case, receiver), which identifies the actual decorator. It is applied to register a function as a signal receiver.
- signal: This is a necessary parameter that denotes the signal to which the receiver function will be attached. It might be post_save, pre_delete, or any other Django signal type that we discussed above. The django.db.models.signals module is used to import these signals.
- sender: The signal sender to which the receiver is connected is specified by this parameter. It is an optional parameter that enables you to further filter the signal by connecting it to a particular sender. if the sender is left bland ( or set to None), any sender’s signal will be connected to the receiver function.
- reciever_function: This is the function that will be registered as the receiver for the signal. It should be able to handle the desired logic when the signal is activated and accept the necessary parameters as specified by the particular signal.
The ‘@receiver’ decorator is placed just above the receiver function (send_notification) in this case. The receiver function (send_notification) is then defined below the decorator. It receives the signal along with any additional arguments associated with the signal.
Here, in this case, the ‘send_notification’ function receives ‘sender’, ‘instance’, ‘created’, and ‘**kwargs’ as parameters.
- sender: The signal sender is represented by the sender parameter. In this case, it refers to the object that triggered the signal. Any model instance that emits a signal act as the sender. In the context of the @receiver decorator, the sender will be the model class specified when connecting the receiver function to the signal.
- instance: The sender model instance that generated the signal is represented by the instance parameter. It contains the actual object that was created or modified.
- created: Whether the instance was newly created (True) or updated (False) when the signal was sent is indicated by the created parameter, which is a boolean value. It helps differentiate between the creation and modification events.
- **kwargs: The function can take any additional keyword arguments supplied along with the signal by passing them in via the **kwargs parameter.
We determine whether the created parameter is True, indicating that a new Post instance has been created, inside the send_notification function. If so, we move on to sending a notification email.
Create a PostForm in the ‘blog/post_form.py’ file.
from django import forms
from blog.models import Post
class PostForm(forms.ModelForm):
class Meta:
model = Post
fields = ['title', 'content']
Create a view to handle the creation of blog posts in the ‘blog/views.py’ file.
from django.shortcuts import render
# Create your views here.
from django.shortcuts import render
from django.http import HttpResponse
from blog.models import Post
from blog.post_forms import PostForm
def create_post(request):
if request.method == 'POST':
form = PostForm(request.POST)
if form.is_valid():
form.save()
return HttpResponse("You have created the Post successfully")
else:
form = PostForm()
return render(request, 'create_post.html',{'form':form})
Create a template for the blog post creation form in the ‘blog/templates/create_post.html’.
<h2> Create a new blog post </h2>
<form method = "post">
{% csrf_token %}
{{form.as_p}}
<button type = "submit"> Create </button>
</form>
Define the URL patterns in the ‘urls.py’ file of the project.
urlpatterns = [
path('admin/', admin.site.urls),
path('create/', create_post, name = "create_post")
]
Then specify the location of templates in your Django project, you need to update the ‘TEMPLATES’ setting in your projects ‘setting.py’.
import os
TEMPLATES = [
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [ os.path.join(BASE_DIR, 'templates')],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
]
Now set up Gmail as the email backend in Django’s ‘setting.py’ file, you can follow these steps:
Open your project ‘setting.py’ file. Add the following code.
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = 'smtp.gmail.com'
EMAIL_PORT = 587
EMAIL_USE_TLS = True
EMAIL_HOST_USER = 'Enter sender email id'
EMAIL_HOST_PASSWORD = 'Enter sender password'
Then open the terminal and run the following command to create the table for Post in the database.
python manage.py makemigrations
python manage.py migrate
After running the above commands, run the URL (http://127.0.0.1:8000/create/) in your browser and you see the form for creating the post.
Fill out the form or create a new post by providing the title and content, then click on the button Create to create the post and send the email notification for the newly created post.
After clicking on the create button, you see the message ” You have created the Post successfully”, now check the mailbox. you will see the email notification for the new post that you have created.
We have created a blog app that sends notifications to users when a new post is created.
Download the Complete Blog Application
Conclusion
In this Python tutorial, we have learned “How to create a signal in Django” and how they can be used to send email notifications when new blog posts are created. We started by knowing the about the signals and their type, then define the model, views, and template for the blog post application and set up a signal receiver function and email backend.
You may also like to read the following articles:
- How to use Python Django pre_save
- Python Django convert date time to string
- Python Django import functions
- JWT Authentication Using Django Rest Framework
I am Bijay Kumar, a Microsoft MVP in SharePoint. Apart from SharePoint, I started working on Python, Machine learning, and artificial intelligence for the last 5 years. During this time I got expertise in various Python libraries also like Tkinter, Pandas, NumPy, Turtle, Django, Matplotlib, Tensorflow, Scipy, Scikit-Learn, etc… for various clients in the United States, Canada, the United Kingdom, Australia, New Zealand, etc. Check out my profile.