【问题标题】:Preventing duplicate signals for post_save in Django 1.4.3防止 Django 1.4.3 中 post_save 的重复信号
【发布时间】:2013-01-22 01:07:35
【问题描述】:

我正在尝试编写一些代码,每次用户修改模型对象时都会发送一封电子邮件。目前,我正在努力让 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 还是新手。您所说的视图/表单代码指的是我创建应用程序时自动生成的views.py,对吗?在这种情况下,我的 view.py 文件完全是空的,没有被改动过。
  • 那么您只是在使用 Django 管理员来修改您的对象吗?否则,你把它保存在哪里?
  • 是的,我在同一个应用文件夹中有一个 admin.py 文件。它的内容实际上由 4 行组成。两个模型导入和两个 admin.site.register("model_name")。我正在使用我相信的默认表格?具有 3 个保存选项的那个。至于我保存它的位置,我认为数据保存在我在项目目录中创建的“test_database.db”文件中。

标签: python django duplicates


【解决方案1】:

您的问题来自这样一个事实,即每次您通过管理界面修改对象时,管理应用程序都会创建代表所做更改的 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. 给你的模型一个通用的超类,并在监听器中使用它来测试

    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
    

【讨论】:

  • 我已尝试实施您概述的第二个解决方案。两个信号的 isinstance(sender, LogEntry) 都返回为 False。我完全迷路了。双重信号可能还有其他原因吗?我听说重复的 post_save 信号是 Django/Python 导入模块方式的结果。
  • 这很奇怪。我早些时候在 Django 1.4 上检查过它,这就是双重信号的原因。你用的是什么版本?只需将 print sender 放在信号处理程序中,让我们看看你得到了什么。
  • 啊,你知道的。打印发送器给了我一个来自模型的信号和一个来自 LogEntry 的信号。你是对的!猜猜这个问题可能是我在第二个解决方案中的 if 语句没有正确编写。 def send_email(sender, **kwargs): if isinstance(sender, LogEntry): print "LogEntry signal received."否则返回:
  • 我使用以下方法进行了导入:from django.contrib.admin.models import LogEntry。然后在 send_email 函数下,写了 if 语句: if isinstance(sender, LogEntry): return, else: #code 发送邮件。我在 else 语句代码下放了一个打印语句,保存时出现了两次。它以某种方式忽略了 LogEntry if 语句。
  • 啊,我想我明白这个问题了。 isinstance 不起作用,因为两个信号都是相同的模型“类型”。但是,发件人的“价值”因人而异。
猜你喜欢
  • 2011-03-30
  • 2014-05-23
  • 2012-10-12
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-10-10
  • 2016-05-04
相关资源
最近更新 更多