未调用 post_save 信号

Posted

技术标签:

【中文标题】未调用 post_save 信号【英文标题】:post_save signal isn't called 【发布时间】:2017-04-06 09:08:27 【问题描述】:

我已经阅读了所有相关问题。

我有两个 Django 项目,信号在一个项目中运行良好,但在第二个项目中不起作用(我只是分别复制粘贴代码和更改名称)。

我有一个订单模型的订单应用程序。应用程序包含在 INSTALLED_APPS 设置中。

我在 apps.py 中有应用配置:

from django.apps import AppConfig


class OrdersConfig(AppConfig):
    name = 'orders'

    def ready(self):
        super(OrdersConfig, self).ready()

        # noinspection PyUnresolvedReferences
        import signals

__init__.py:

default_app_config = 'orders.apps.OrdersConfig'

最后,signals.py:

@receiver(post_save, sender=Order)
def order_save(sender, instance, created, **kwargs):
    print 'Post save'
    if created:
        print 'Created'
        send_email_new_order.delay(settings.MODERATOR_EMAIL, instance.pk)

并且信号没有被调用。为什么?

Django 1.10.3.

【问题讨论】:

尝试在模型末尾定义信号。 【参考方案1】:

什么时候会触发 post_save?

文档内容:在保存方法的末尾。

真正含义:在save方法成功完成的最后。

什么时候不触发信号?

    如果save方法没有成功保存对象(比如出现IntegrityError时) 当您致电MyModel.objects.update() 当您覆盖save 方法并忘记调用超类方法时。 当您的信号接收器未成功注册时。

如何注册接收者

最简单的方法是像你一样使用@receiver 装饰器。另一种方法是使用

from django.db.models.signals import pre_save

pre_save.connect(order_save, sender='app_label.MyModel')

这段代码应该放在哪里?

如今,manual 声明

严格来说,信号处理和注册码是可以活的 任何你喜欢的地方,虽然建议避免 应用程序的根模块及其模型模块,以最小化 导入代码的副作用。

这可能就是为什么在本例中您创建了一个名为 signals.py 的文件并将您的代码放入其中并使用 AppConfig 类和 ready 方法解决所有问题的原因。但有趣的是,Django 1.6 manual 说:

您可以将信号处理和注册代码放在您喜欢的任何位置。 但是,您需要确保它所在的模块 尽早导入,以便信号处理在之前注册 需要发送任何信号。这使您的应用程序的 models.py 很好 放置信号处理程序注册的地方。

因此,如果您在注册信号接收器时遇到问题,您实际上可以尝试将您的代码放入 models.pyviews.py 并忽略 AppConfig 中的位(甚至可能完全删除 AppConfig)

如果您想在 AppConfig 中进行注册,并且遇到@reciever 和/或导入问题,您可以尝试

from django.db.models.signals import pre_save
from app_label.signals import my_reciever

def ready(self):
    pre_save.connect(my_reciever, sender='app_label.MyModel')

如何避免重复?

信号会被触发两次吗?确保只注册一次接收器。如果您在AppConfig 中注册,请不要在models.py 中使用,反之亦然

【讨论】:

如果你把你的信号放在你的模型文件中,是 sender=self 吗?【参考方案2】:

您确定导入了正确的signals 吗? (print('hi, signals here') 在模块中?)

您可能还想使用绝对合格的导入 (import orders.signals) 或相对的导入 (import .signals as signals)。

【讨论】:

嗯,用打印检查,它被调用了两次——可以吗? 这应该不是问题。【参考方案3】:

您是否还有另一个名为 signals 的应用程序?

ready方法中尝试相对导入:from . import signals

【讨论】:

以上是关于未调用 post_save 信号的主要内容,如果未能解决你的问题,请参考以下文章

仅在事务完成后触发 post_save 信号

从 django post save 信号产生一个线程可以吗?

多对多字段保存到数据库后调用 post_save

Django 从 post_save 信号访问 ManyToMany 字段

芹菜 + Django 信号

关于 post_save 信号和 created 参数