Django signals
Tags: django
Published: 2023-04-24 17:35:37

Good day geeks!!

Signals in django are a way for your models to communicate to each other when an event is fired. For those who have worked with JavaScript, you have most likely come across the .addEventListener() method which is called only when an event is fired, this method works same way as django signals but this time, it is called when one part of two related models is saved, deleted, updated etc. 

Below are some of the available events that can be fired.

1. pre_save and post_save:
These events are called when before a model is saved and after a model is saved respectively.
2. pre_delete and post_delete:
These events are called before or after a model is deleted respectively.
3. m2m_changed:
Called when a many to many field on a model changes.
4. request_started and request_finished:
Called before and after a HTTP request is stated or finished respectively.

**Creating a working signal**

One very important part of my django application where I use signals is when I'm working with a model which has a one to one relationship with the user model. In this tutorial, I'll be using a `Profile` model. Every user must have a profile which is an extension of the user model. You could actually do that in different ways, one of which is to override the save method of the user model and then create a profile for the created user. But let's say we want to keep things nice and simple, signals will be the right way to go.

I'll assume you already know how to start a django project so I'll be skipping that part. Head over to your app's models.py file and create this Profile model.

```
from django.contrib.auth import get_user_model
import uuid

# user object
User = get_user_model()


class Profile(models.Model):
    id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)
    user = models.OneToOneField(User, on_delete=models.CASCADE)
    friends = models.ManyToManyField("self", blank=True)
    picture = models.ImageField(upload_to="dps")
	
    def __str__(self):
        return self.user.username


```

Alright! we have our profile model set up, let's make migrations and migrate to the database

```
$ python manage.py makemigrations
$ python manage.py migrate
```

Now we want the profiles to be automatically created when we create a user instance. To do that, create a file in your app's directory and name it signals.py

```
#signals.py

from django.db.models.signals import post_save
from django.dispatch import receiver
from .models import Profile, User

@receiver(post_save, sender=User)
def create_profile(sender, instance, created, **kwargs):
    if created:
        Profile.objects.create(user=instance)
        print(f"Profile for {instance.username} created successfully!!")

```

Here, I used the post_save signal because our profile will be created after the user has been successfully created.

we need to let our application know about this file so head over to your apps.py file which was created when you ran `$ python manage.py startapp <appname>` and add this piece of code to it.

```
class AccountConfig(AppConfig):
    default_auto_field = 'django.db.models.BigAutoField'
    name = 'account'
    
    # add this
    def ready(self):
        from . import signals
```

Now, we are all set up. For this to work, make sure that your app is registered in INSTALLED_APPS as `<app_name>.apps.<Appname>Config`

You can now create profile instances just on the fly. Thanks for reading guys, do leave a comment below. see you on the next one.