Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Preventing duplicate signals for post_save in Django 1.4.3

I'm trying to write some code that sends an email every time one of the users modifies a model object. Currently, I'm working on having the one of the methods in models.py receive a post_save signal. I realize it's a well known fact that the post_save signal is usually sent twice, thus, the workaround is to utilize the dispatch_uid parameter. I have done this, but for some strange reason, I continue to receive two signals. Here's the code in my app's model.py file.

from django.db import models
from django.db.models.signals import post_save

def send_email(sender, **kwargs):
      print "Signal sent." #just a placeholder

post_save.connect(send_email, dispatch_uid="unique_identifier")

class Library_Associates (models.Model):
      first_name = models.CharField(max_length = 200)
      last_name = models.CharField(max_length = 200)

  department_choices = (
        ('ENG', 'Engineering'),
        ('ART', 'Arts and Sciences'),
        ('AFM', 'Accounting and Financial Managment'),
        ('MAT', 'Mathematics'),
  )

  department = models.CharField(max_length = 3, choices = department_choices, default = 'ENG')

  pub_date = models.DateTimeField ('date published')

  def __unicode__(self):
        return self.first_name

  class Meta:
        verbose_name_plural = 'Library Associates'

class Info_Desk_Staff (models.Model):
      first_name = models.CharField(max_length=50)
      last_name = models.CharField(max_length=50)
      salary = models.IntegerField()
      hours_worked = models.IntegerField()

      def __unicode__(self):
            return self.first_name

      class Meta:
            verbose_name_plural = 'Info Desk Staff'

I already restarted the server several times, reset/deleted all the data for the app and I continue to still receive two signals. Is there something inherently wrong with my code? Any suggestions or insight would be greatly appreciated! Thanks!

like image 740
Kenny Avatar asked Oct 16 '25 17:10

Kenny


1 Answers

Your problem comes from the fact that each time you modify an object via the admin interface, admin app creates the django.contrib.admin.models.LogEntry instance that represents changes made.

Because you are listening to post_save on all objects, your listener is called twice - once for your model, and the second time for the LogEntry model.

List of possible solutions includes:

  1. Registering your listener separately for each of your models (e.g. select your models somehow and do it in a loop) using the sender argument in the post_save method.

    for model in get_models():
        post_save.connect(send_email, sender = model, dispatch_uid='unique_identifier')
    
  2. Check if the sender sent to the listener is not an instance of django.contrib.admin.models.LogEntry

    from django.contrib.admin.models import LogEntry
    ...
    
    def send_email(sender, **kwargs):
        if isinstance(sender, LogEntry):
            return
    
  3. Give your models a common super class and use that for testing in the listener

    class MyModel(models.Model):
        pass
    
    class Library_Associates (MyModel):
        ...
    class Info_Desk_Staff (MyModel):
        ...
    
    def send_email(sender, **kwargs):
        if not isinstance(sender, MyModel):
            return
    
like image 191
zifot Avatar answered Oct 19 '25 07:10

zifot



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!