How to use Signal correctly in Django 1.6

  • 2020-04-02 13:46:02
  • OfStack

The short answer is: signal is the last thing to be considered when other methods are not available.

When new django developers learn about signal, they tend to be happy to use it, use it where they can, and feel like django experts.

Many developers will also django signal and asynchronous message queue, such as celery. Signal is synchronous processing, so by signal invocation process of large capacity and unable to improve performance. In fact, these need large processing process will be moved to the signal of being seen as a bad habit.

1. When to use signal

Do not use signal when:

Signal is closely related to a model and can be moved to the save() of that model
Signal can use the model manager instead
Signal is closely related to a view and can be moved to that view
Signal can be used in the following situations:

Signal's receiver needs to modify multiple models at the same time
When the same signal of multiple apps is directed to the same receiver for processing
When the cache is cleared after a model is saved
When no other method is available, but a called function is needed to handle certain problems
2. Alternative to Signal

Manager using the mod

The following code demonstrates that when the user creates the Event model, the administrator needs to be notified, and if post_save() in the model is overwritten, additional logic needs to be added to distinguish between the user and the administrator:


# myapp/managers.py
 from django.db import models

 class EventManager(models.Manager):

 def create_event(self, title, start, end, creator):
 event = self.model(title=title, start=start, end=end, creator=creator)
 event.save()
 event.notify_admins()
 return event

Set the model manager in the model:


# myapp/models.py
 from django.conf import settings
 from django.core.mail import mail_admins
 from django.db import models

 from model_utils.models import TimeStampedModel
 from .managers import EventManager

 class Event(TimeStampedModel):

 STATUS_UNREVIEWED, STATUS_REVIEWED = (0, 1)
 STATUS_CHOICES = (
 (STATUS_UNREVIEWED, "Unreviewed"),
 (STATUS_REVIEWED, "Reviewed")
 )

 title = models.CharField(max_length=100)
 start = models.DateTimeField()
 end = model.dateTimeField()
 status = models.IntegerField(choices=STATUS_CHOICES, default=STATUS_UNREVIEWED)
 creator = models.ForeignField(settings.AUTH_USER_MODEL)
 objects = EventManager()

 def notify_admins(self):
 subject = "{user} submitted a new event!".format(user=self.creator.get_full_name())
 message = """TITLE: {title}
 START: {start}
 END: {end}""".format(title=self.title, start=self.start, end=self.end)
 mail_admins(subject=subject, message=message, fail_silently=False)

When create_event() is used in the view instead of create(), the administrator is notified.

Validate the model in other code

If you use pre_save signal to validate a model, you should try to write your own validator instead. If the validation is through ModelForm, do it by rewriting clean().

Use the model's save() and delete()

If you use pre_save or post_save signal, if you can, move the code to the save() method of the model.

Also if you use pre_delete or post_delete signal, if you can, move the code to the delte() method of the model.

Use other code instead of signal

If possible, we can implement signal's logic using other helper programs.


Related articles: