Best practices for Django signals: register in ready(), use custom signals, and avoid side-effects.
Django Signals Best Practices
# Connect in apps.py ready() - not at module level
class BlogConfig(AppConfig):
name = "blog"
def ready(self):
import blog.signals
# blog/signals.py
from django.db.models.signals import post_save, pre_delete
from django.dispatch import receiver, Signal
post_published = Signal() # custom signal
@receiver(post_save, sender=Post)
def on_post_saved(sender, instance, created, **kwargs):
if created:
instance.author.profile.increment_post_count()
@receiver(post_published)
def notify_followers(sender, post, **kwargs):
msg = post.author.name + " published: " + post.title
for follower in post.author.followers.all():
Notification.objects.create(recipient=follower, message=msg)
@receiver(pre_delete, sender=Post)
def cleanup_files(sender, instance, **kwargs):
if instance.image:
instance.image.delete(save=False)
# Fire custom signal
post_published.send(sender=Post, post=instance)