I am experimenting with Django Signals.
In the documentation, it is written that there are two ways to connect a receiver to a signal.
Signal.connect
methodreceiver
decoratorHere's what I have implemented:
# models.py
from django.db import models
from django.dispatch import receiver
from .signals import demo_signal
class Demo(models.Model):
demo = models.CharField("demo", max_length=50)
def send_signal(self):
demo_signal.send(self)
print('signal sent')
def connect_receiver(self):
demo_signal.connect(signal_handler, sender=self)
@receiver(demo_signal, sender=Demo)
def signal_handler(**kwargs):
print('signal handled')
# signals.py
from django.dispatch import Signal
demo_signal = Signal()
However, when I call send_signal
method, I don't get signal handled
printed out unless I call connect_receiver
method first.
In [1]: demo = Demo.objects.get(pk=2)
In [2]: demo
Out[2]: <Demo: Demo object (2)>
In [3]: demo.send_signal()
signal sent
In [4]:
And Interestingly enough, after implementing pre_delete_handler
as follows, without connecting, calling delete
method does call pre_delete_handler
@receiver(pre_delete, sender=Demo)
def pre_delete_handler(instance, **kwargs):
print(instance, kwargs)
print('pre delete')
Receiver does receive the signal without sender
argument:
@receiver(pre_delete)
def pre_delete_handler(instance, **kwargs):
print(instance, kwargs)
print('pre delete')
But how can I make it listen to a specific Model?
Why does sending signal does not call its receiver(decorated signal_handler
) in my case?
Wow... Just a moment after posting this question, I have figured out why.
So, if I want to call model specific receiver, I have to pass a class instead of an instance. That is, self.__class__
.
class Demo(models.Model):
demo = models.CharField("demo", max_length=50)
def send_signal(self):
demo_signal.send(sender=self.__class__)
print('signal sent')
@receiver(demo_signal, sender=Demo)
def signal_handler(**kwargs):
print('demo signal handled')