Django has been into existence from quite some time now and it is one of the most popular frameworks for backend and REST API development, not only because it has a great developer community behind it but also because of so many cool and comprehensive features. Today, we’ll try and explore one of these features. While developing Python Backends or APIs there can be a lot of use case where we might need to take some event driven actions or complete some backend jobs.
Let’s understand with an example, we all know that Django has its own very powerful ORM tool to manage database transactions. In some cases when we perform CRUD operations to a database table using Django models, we might need to perform some additional actions.
So, if there is a model called Product, and it is associated with images. When we delete a product from the database, we need to delete images related to the product stored in the file system, we need to perform this action during the deletion operation. We can do this process in views. But to make your code follow clean code principles, Django provides us an elegant way to handle these situations. Django has concept - called Signals.
Django's signals are utilities that allow us to associate events with actions. We can develop a simple function that runs when a signal calls it. We use @receiver decorator for the receiver function for which we need to execute when specific signal is called.
Django provides a set of built-in signals that let user code get notified by Django itself of certain actions. These include some useful notifications:
- django.db.models.signals.pre_save & django.db.models.signals.post_save : Sent before or after a model's save() method is called
- django.db.models.signals.pre_delete & django.db.models.signals.post_delete : Sent before or after a model's delete() method or queryset's delete() method is called
- django.db.models.signals.m2m_changed : Sent when a ManyToManyField on a model is changed
- django.core.signals.request_started & django.core.signals.request_finished : Sent when Django starts or finishes an HTTP request
In this blog post we will implement pre_save , post_save and pre_delete signal use cases.
Most of the Django's signals sends 2 arguments to the signal receivers i.e
- Sender: The model class for which we are sending the signals
- Instance: The actual instance of the model that is being modified (Create, Update or Delete)
Now in our example of Product model. Let's say if we want to send email notification for the user if any new product is created in the database. We can use post_save signal for this purpose.
Along with the Sender, Instance arguments post_save signal sends other user useful argument called created which is useful to understand if the object is being created or updated.
After writing the post_save signal our models.py will look like the following.
Let's say if we want to send email notification for the user if any product price is dropped. We can use pre_save signal for this purpose.
Here in this signal the instance holds the data that is not saved yet, so we can compare this data with the original record data and perform specific business actions.
After writing the pre_save signal our models.py will look like the following.
In our current example let's say if there are any images associated with the product, we need to remove the images associated with the Product. So, we can use pre_delete signal for this purpose.
After writing the pre_delete signal our models.py will look like the following.
We can write our own Custom signals for the models. Let's say if we want to record the number of views that a product received, we can write our own signal, and using this signal we can record the User who viewed the Product and also update number of views that a product received.
To create a custom Signal, create a file called signals.py in your application.
To run the receiver function, we need to create receivers.py which contains the receiver function which will be called when the signal is dispatched. In receivers.py we need to connect the signal and receiver function.
In order to make the receiver function work when the custom signal is called, we need to make sure we import these receivers in the app config i.e in our apps.py
Now we are all set to use the signal. To use our custom signal, we use send method of the signal along with the Sender and Other arguments.
To learn more about signals, click here to access official docs.
Disclaimer: This is a personal [blog, post, statement, opinion]. The views and opinions expressed here are only those of the author and do not represent those of any organization or any individual with whom the author may be associated, professionally or personally.