Introduction to Django Signals
This guide will explore how to use signals in Django as a method to pre-process and post-process data on its way to a database or just after saving to a database.
Oct 28, 2020 • 5 Minute Read
Introduction
When saving data to a database, there are unique use cases where the business requirement of an application may require some processing just before or after saving the data. This means there should be a way to know when data is about to be saved or has just been saved in the database by the Django model method save().
One possible way is to override the save() method on each model.
A neater and more efficient way is to use Django signals. These components work on the concept of senders and receivers. The sending component is usually the model, and the receiving component is usually the processing function that works on the data once it receives a notification that the data is just about to be saved or has just been saved.
This guide will explore how to use signals in Django as a method to pre-process and post-process data on its way to the database or just after saving to the database. It assumes you have at least beginner level knowledge in Django and a general understanding of the Django MVC, especially the models component. An introductory guide to Django can be found here, and a refresher guide on Django models can be found here.
Use Case Scenario
Consider a use case where you have an ecommerce Django app with an orders and inventory model. The business logic is such that before an order is saved, the inventory should be checked to ensure the item is in stock.
Also, after an order is saved, there should be a logic to send a notification that the order has been received. Below is a codeblock for the sample models.
from django.db import models
from django.contrib.auth.models import User
class Inventory(models.Model):
item = models.CharField(max_length=20)
item_code = models.IntegerField()
item_condition = models.CharField(max_length=50)
quantity = models.IntegerField()
def __str__(self):
return self.item
class Order(models.Model):
ord_number = models.CharField(max_length=20)
inventory_item = models.ForeignKey(Inventory)
ordered_by = models.ForeignKey(User)
quantity = models.IntegerField()
def __str__(self):
return self.ord_number
Pre-save Signal
A pre-save signal is used in situations where logic has to be executed before data is saved to a database. In your case, this involves determining whether an order is valid by checking whether the item exists in inventory. The code block below defines a function to achieve this objective. The function can live within models.py.
from django.db.models.signals import pre_save
def validate_order(sender, instance, **kwargs):
if instance.quantity < instance.inventory_item.quantity: # order can be fulfilled
instance.save()
else:
# write logic to reject save and give message why
pre_save.connect(validate_order, sender=Order)
In the above code block, you have defined your business logic in the validate_order() function and using the pre_save function, and you have connected the receiver function to the sender, which is the Order model.
Post-save Signal
This is where you notify the user that the order has been successfully received. The post_save logic is just a normal function, the receiver function, but it's connected to a sender, which is the Order model. The code block below demonstrates the sample receiver function as a post-save.
from django.db.models.signals import post_save
from myapp.utils import send_notification
def notify_user(sender, instance, **kwargs):
send_notification(instance.ordered_by)
post_save.connect(notify_user, sender=Order)
With this, once an order is successfully placed, the client will be notified via email or text, depending on what the business use case demands.
Conclusion
With knowledge of Django signals, you can now build robust web apps that can pre-process data during pre-save and post-save. This flexibility also allows you to build customized workflows that better address the needs of specific use cases.
To build on this guide, research more on signals and receivers, including how they work and if they can be overridden. Overridding gives the programmer the ability to customize pre-built functions. You might also bee interested in how a pre-save or post-save signal differentiates between a new record save and an update save for an existing record.