The closest example to understand signals is a trigger, as in a SQL trigger used to perform a certain method on executing certain DML queries. Signals let a sender notify another receiver that some event has occurred and some action needs to be performed. In Django, singals are extremely useful for decoupling modules. They allow a low-level Django app to send events for other apps to handle without creating a direct dependency. It provides a mechanism to send and receive messages between different parts of an application, called the signal dispatcher.
Now, let's look how a signal and reciever send messages/information on certain events. Firtsly, a signal is an object corresponding to a particular event. For example, we might define the following signal to represent a employee has logged in,
- from django.dispatch import Signal
-
- employee_login = Signal(providing_args=["id", "time"])
Signals send messages by calling the send() method on the signal instance and passing in a sender argument, along with the arguments specified above for the employee_login signal,
- class Employee:
- def mark_logged_in(self, id, time):
- ...
- employee_login.send(sender=self.__class__, id=id, time=time)
Second comes the reciever, these are callables that are connected to a particular signal. When the signal sends its message, each connected receiver gets called synchronously. The reciever method signatures should match that of the signal’s send() method uses. You connect a receiver to a signal using the @receiver decorator as shown below,
- from django.dispatch import receiver
- from employee import signals
-
- @receiver(signals.employee_login)
- def add_employee_on_todays_list(sender, id, time, **kwargs):
- ...
So that's it with the basics of the signals dispatcher. You have signals and receivers, the receivers can connect to the signals, and the signals send messages synchronously to any connected receivers.
Why use a signal? Let's answer this by an example, you have two apps and one app wants to trigger a method in an app it already knows about, then we don’t need to use signals. The app should just import the method it needs and call it directly. But if the scenario is reversed, where one app is unaware of the methods the other app has that needs to be triggered, in this case, signals are a great way of providing a ‘hook’ which the second app can exploit by connecting a receiver to it. Signals provide loosely coupled and highly cohesive architecture and this is because there are no circular dependencies between the apps.