【问题标题】:Django post save signal getting called twice despite uid尽管有uid,Django post save 信号被调用了两次
【发布时间】:2012-08-14 07:42:12
【问题描述】:

我已经使用 @receiver 装饰器在回调中注册了我的信号

@receiver(post_save, sender=User, dispatch_uid='ARandomUniqueString') 
def do_callback(sender, **kwargs):

我已将from app.signals import * 代码放在__init__.py 中,我可以看到它被导入了两次,我认为没有好的方法可以修复它,这可能是由于installed apps 中的settings.py 而发生的。我不明白为什么尽管使用dispatch_uidmodelInstance.save 只被调用一次,它仍然运行do_callback 两次。有什么建议吗?

【问题讨论】:

    标签: python mysql django signals


    【解决方案1】:

    好的,所以我将导入移动到 views.py(或 models.py,虽然它只被导入一次,但它被调用了两次。

    问题是在创建和保存对象时调用了post_save 信号。我不知道为什么,所以我添加了一个现在可以使用的解决方法

    created = False
    
        #Workaround to signal being emitted twice on create and save
        if 'created' in kwargs:
            if kwargs['created']:
                created=True
    
        #If signal is from object creation, return
        if created:
            return
    

    编辑:

    post_save 被调用了两次,因为我使用了 .create(...),这相当于 __init__(...).save()

    结论

    dispatch_uid 确实有效,单次导入仍然是一个好习惯。

    【讨论】:

    • 如何区分 init 时 created = False 和当我们更新/修改对象时也返回 created=False?
    • @Pratik Mandrekar 您将锻炼 if 语句放入哪个文件?我想我现在面临的问题可能与您当时所面临的类似。
    【解决方案2】:

    我对 post_save 和 post_delete 信号也有同样的问题。尽管设置了 dispatch_uid,但似乎会话对象和 LogEntry 对象也被保存,并创建了多个信号。

    对我有用的是:

    from django.contrib.admin.models import LogEntry
    from django.contrib.sessions.models import Session
    
    ....
    
    if sender in [LogEntry, Session]:
        return 
    else:
        # do your thing here
    

    【讨论】:

      【解决方案3】:

      我刚刚遇到了同样的问题。我有一个接收器,它做一些重要的事情,在 Django 中每次新创建模型实例时必须只做一次。所以,我使用了post_save 信号,但是为了创建每个新模型实例而调用了两次,就像Profile.objects.create(...) 一样。 这个问题的解决方案是kwargs 附带的created 标志。以下是如何使用该标志来确保您的预期操作只执行一次:

      @receiver(post_save, sender=Profile)
      def publish_auction(sender, **kwargs):
          if kwargs['created']:
              kwargs['instance'].send_email_confirmation()
      

      我尝试了来自Django docsdispatch_uid 建议。它不起作用,但我上面粘贴的代码有效。

      【讨论】:

        【解决方案4】:

        我已将from app.signals import * 代码放入__init__.py

        你不应该在你的__init__.py文件中放任何东西。

        如果您将其从 __init__.py 中删除,并将其添加到您的 models.py 的底部,它应该可以解决您的问题。

        您还应该避免“盲目”导入from foo import *

        【讨论】:

        • 我的signals.py 使用models.py,虽然我可以做一些事情来避免这种循环依赖,但它违背了流程。解决了我只在__init__.py 中导入do_callback 而不是from app.sgnals import *
        猜你喜欢
        • 2016-03-19
        • 1970-01-01
        • 2019-10-06
        • 1970-01-01
        • 2020-10-01
        • 2014-02-20
        • 1970-01-01
        • 2020-01-31
        • 1970-01-01
        相关资源
        最近更新 更多