【问题标题】:Django pre_save signal does not workDjango pre_save 信号不起作用
【发布时间】:2011-09-03 11:13:51
【问题描述】:

我通过以下方式测试了Django的“pre_save”信号,但都无法捕捉到信号。

$

from django.db.models.signals import pre_save
import logging

def my_callback(sender, **kwargs):
    logging.debug("======================================")
pre_save.connect(my_callback)
  1. 在 manage.py shell 中运行上述代码: 然后我运行我的网站,看到 models.save() 成功了,但是回调函数没有运行。

  2. 或者,我再次在 shell 上运行上述代码,然后在 shell 中运行 models.save()。 “保存”再次运行良好,但回调函数仍然没有任何反应。

  3. 最后,我将上面的代码嵌入到__init__.py 文件中,然后在网站上运行 save() 函数。仍然没有任何反应。

请您帮我弄清楚为什么 pre_save 信号似乎不起作用?

【问题讨论】:

  • 您是否尝试在models.py 文件中添加代码?

标签: python django django-signals


【解决方案1】:

您没有为一个设置发件人类。

from django.db.models.signals import pre_save
from myapp.models import MyModel
import logging

def my_callback(sender, **kwargs):
    logging.debug("======================================")
pre_save.connect(my_callback, sender=MyModel)

其次,如果您使用的是 Django 1.3,您应该使用新的装饰器语法。

# Inside your models.py
from django.db import models
from django.db.models.signals import pre_save
from django.dispatch import receiver

class MyModel(models.Model):
    field1 = models.TextField()
    field2 = models.IntegerField()

@receiver(pre_save, sender=MyModel)
def mymodel_save_handler(sender, **kwargs):
    logging.debug("======================================")

应该可以,但我还没有测试过代码,所以请告诉我它是否仍然损坏。

【讨论】:

  • 您不需要指定发送者类,也不需要使用装饰器语法。它不起作用的原因不是以上任何一个,这是因为他将信号附加到不同线程中的保存发生的位置。
  • 请注意,要使@receiver 代码正常工作,您还需要从 django.dispatch 导入接收器
  • 由于某种原因,此代码仅在信号接收器位于信号发射器所在的同一 model.py 中时才有效(模型)。
【解决方案2】:

Eric 的回答之所以起作用,是因为他让您在 models.py 中连接信号,这样当您通过网站保存模型时,信号处理程序与信号触发程序处于同一进程中。

在示例 1 和 3 中,很容易看出它们为什么不起作用 - 您将保存在与信号接收器正在收听的不同进程(网站)中。

我希望我能更好地理解为什么示例 2 也被破坏了,但我只是在我自己的项目中调试了一个类似的问题,同时在 shell 中测试信号,这绝对与信号发送器和接收器无法“看到”每个有关其他。

【讨论】:

  • 我不知道这是否是正确的解释,但这绝对是有趣的,值得被批评或投票。但我不明白为什么它会是一个不同的线程或进程......
  • 这是一个不同的进程,因为一个是 manage.py shell session,另一个是 manage.py runserver... 这是相同的代码库,但它们是独立运行的,因此对 shell 中的对象进行了更改(信号处理程序的连接)不会影响 Web 服务器中的等效对象
  • (很确定“进程”是正确的术语,而不是我在评论埃里克的回答时使用的“线程”)
  • 是的,我认为它适用于 1,但如果它是 django 应用程序 init.py(两者都不是 2),则不适用于 3。另外,这个logging.debug 对我来说似乎非常可疑 => 看我的回答
  • 同意大约 3,只要代码在网络服务器中重新加载
【解决方案3】:

logging.debug() 使用的是根记录器,默认处理程序级别为 30('WARNING')。

=> logging.debug('something') 只是什么都不做(DEBUG 级别为 10 http://docs.python.org/2/library/logging.html

应该使用另一个自定义记录器来完成相同的测试,或者这样做:

l = logging.getLogger()
l.setLevel(10)
def my_callback(sender, **kwargs):
    logging.debug("======================================")
pre_save.connect(my_callback)

最初的问题没有包含足够的信息来了解这是否是 OP 面临的真正问题(或部分问题)。
但肯定 OP 的代码不适用于我的 ./manage.py shell

【讨论】:

    【解决方案4】:

    django signals doc 中所述,pre_save 信号接受 3 个唯一参数(不是关键字参数),因此,您需要编辑您的 my_callback 函数,如下所示:

    def my_callback(sender,instance, using, **kwargs):
        logging.debug("======================================")
    

    【讨论】:

    • 实际上这些参数不是参数,而是存储在 kwargs 字典中的值。
    • 嗯,这实际上是一回事。但是 Django 文档确实说信号接收器应该接受 (sender, **kwargs),我猜是为了将来的兼容性,而不是命名信号的特定参数。
    猜你喜欢
    • 2011-12-22
    • 2017-04-26
    • 2014-04-15
    • 2017-04-07
    • 2010-11-02
    • 2018-08-09
    • 2015-01-22
    • 1970-01-01
    • 2021-04-21
    相关资源
    最近更新 更多