2

我正在尝试编写一些代码,每次用户修改模型对象时都会发送一封电子邮件。目前,我正在努力让 models.py 中的一种方法接收 post_save 信号。我意识到 post_save 信号通常被发送两次是众所周知的事实,因此,解决方法是利用 dispatch_uid 参数。我已经这样做了,但出于某种奇怪的原因,我继续收到两个信号。这是我的应用程序的 model.py 文件中的代码。

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'

我已经多次重新启动服务器,重置/删除了应用程序的所有数据,但我仍然继续收到两个信号。我的代码有什么本质上的问题吗?任何建议或见解将不胜感激!谢谢!

4

1 回答 1

4

您的问题来自这样一个事实,即每次您通过管理界面修改对象时,管理应用程序都会创建django.contrib.admin.models.LogEntry代表所做更改的实例。

因为您正在收听所有对象的 post_save,所以您的侦听器被调用了两次 - 一次用于您的模型,第二次用于 LogEntry 模型。

可能的解决方案列表包括:

  1. 使用post_save方法中的sender参数为您的每个模型分别注册您的侦听器(例如,以某种方式选择您的模型并循环执行) 。

    for model in get_models():
        post_save.connect(send_email, sender = model, dispatch_uid='unique_identifier')
    
  2. 检查发送到监听器的发送者是否不是 django.contrib.admin.models.LogEntry 的实例

    from django.contrib.admin.models import LogEntry
    ...
    
    def send_email(sender, **kwargs):
        if isinstance(sender, LogEntry):
            return
    
  3. 为您的模型提供一个通用的超类,并将其用于在侦听器中进行测试

    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
    
于 2013-02-07T15:23:58.610 回答