Signals in Django

Adrienne Domingus
2 min readOct 1, 2016

One of the benefits of the app structure of Django is that disparate pieces of your project don’t necessarily know about each other. But sometimes something happening in one app needs to trigger an action in another. Signals to the rescue.

Built in Signals

Some signals, such as post_save, come built in. They are called every time an instance of their sender is saved. For example:

@receiver(post_save, sender='app.Model', dispatch_uid='example_method')
def example_method(sender, instance=None, created=None, update_fields=None, **kwargs):
...

That’s a receiver that is called every time a signal is passed. To break it down a little:

  • This is in a file called signals.py, within the app that holds the pieces relevant to what the function will change. Not usually the same app as the sender model
  • It uses the receiver decorator, to declare that the function that follows is the receiver of a signal.
  • The post_save and sender arguments to the decorator that it will be called every time an instance of Model is saved.

The function takes:

  • An instance (the instance of the Model that was saved)
  • Whether the instance was just created or not — you may want different behavior depending on whether it was created or updated
  • update_fields, which is an optional list of the fields that were changed on the instance, in case you want the behavior to differ based on what changed. You’d have to call it like so:
self.user.save(update_fields=['first_name', 'last_name])

If you don’t want to pass update_fields, you can just call .save() on your object like you would any other time, and the signal will be sent.

Custom Signals

Sometimes the built in signals just don’t meet your needs. Here’s how to define a custom one (within the signals.py file of the app where the receiver will be defined):

from django.dispatch import Signaluser_attributes_changed = Signal(providing_args=["user", "attributes"])

You then need to call it manually whenever you want the signal sent:

from app.signals import user_attributes_changeddef some_method: