Author avatar

Kimaru Thagana

Introduction to Django Signals

Kimaru Thagana

  • Oct 28, 2020
  • 5 Min read
  • 161 Views
  • Oct 28, 2020
  • 5 Min read
  • 161 Views
Web Development
Django
Back End Web Development
Server-side Frameworks

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.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
python

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.

1
2
3
4
5
6
7
8
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)
python

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.

1
2
3
4
5
6
7
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)
python

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.

1