Skip to main content
 首页 » 编程设计

python之防止 Django 1.4.3 中 post_save 的重复信号

2025年05月04日33shanyou

我正在尝试编写一些代码,在每次其中一个用户修改模型对象时发送一封电子邮件。目前,我正在努力让 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' 

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

请您参考如下方法:

您的问题来自这样一个事实,即每次您通过管理界面修改对象时,管理应用程序都会创建 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. 检查发送给监听器的sender是否不是django.contrib.admin.models.LogEntry的实例

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

    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