Connecting Models with Pre-save and Post-save Signals

Tutorial 2 of 5

Introduction

In Django, models are an essential part of how your data is stored and manipulated. When you need to perform certain actions before or after saving a model, you can use Django's pre-save and post-save signals.

In this tutorial, we'll learn how to connect models with pre-save and post-save signals and use them to automate some tasks.

You will learn:
- What pre-save and post-save signals are in Django
- How to connect models to these signals
- How to use these signals to automate tasks

Prerequisites:
- Basic understanding of Python
- Basic understanding of Django and its ORM

Step-by-Step Guide

Pre-save and Post-save Signals

In Django, signals are a kind of messaging system that allows certain senders to notify a set of receivers when some action has taken place. They're especially useful when you need to execute some code each time a certain model's save method is called.

Pre-save signals are dispatched before a model's save() method is called, while post-save signals are dispatched after the save() method.

Connecting Models to Signals

To connect a model to a signal, we use the signal's connect() method. This method takes a receiver function that will be called each time the signal is sent. The receiver function should accept two arguments: the sender (the model class) and the instance (the actual instance of the model being saved).

Using Signals to Automate Tasks

Signals can be used to automate tasks that need to happen before or after a model is saved. For example, you might want to automatically create a related object each time a certain model is saved.

Code Examples

Let's say we have a Profile model that should be automatically created for each User that is saved. Here's how we can do this with a post-save signal.

from django.db import models
from django.contrib.auth.models import User
from django.db.models.signals import post_save
from django.dispatch import receiver

class Profile(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)

In the code above, we first import the necessary modules. We then define a Profile model that is related to the User model.

We then define a receiver function create_profile(). This function is connected to the post_save signal of the User model. Each time a User is saved, Django will call this function.

In the create_profile() function, we check if the User instance was just created. If so, we create a related Profile instance.

Summary

In this tutorial, we learned about pre-save and post-save signals in Django. We learned how to connect models to these signals and how to use these signals to automate tasks.

For further learning, you can explore other types of signals in Django, such as pre-delete and post-delete.

Practice Exercises

  1. Create a Book model that has a title field. Each time a Book is saved, use a post-save signal to automatically create a Summary model that is related to the Book. The Summary model should have a content field that defaults to an empty string.

  2. Modify the create_profile() function from the code example above to also set a default value for a bio field in the Profile model. The bio field should be a TextField that defaults to "This is my bio."

  3. Create a pre_save signal for the User model that checks if the email field is unique. If it's not, raise a ValidationError.

Remember, the key to learning is practice! Try to do these exercises without looking at the solutions. Good luck!