Django,post_save 信号恢复。如何绕过信号触发

Nix*_*Nix 1 django google-app-engine signals djangoappengine

我有一种情况,当我的一个模型被保存时,MyModel我想检查一个字段,并在任何其他模型中触发相同的更改some_key.

代码工作正常,但它递归调用信号。结果我在浪费 CPU/DB/API 调用。我基本上想在.save(). 任何建议期间绕过信号?

class MyModel(models.Model):
    #bah
    some_field = #
    some_key = #
Run Code Online (Sandbox Code Playgroud)
#in package code __init__.py 
@receiver(models_.post_save_for, sender=MyModel)
def my_model_post_processing(sender, **kwargs):
 # do some unrelated logic...
 logic = 'fun!  '


 #if something has changed... update any other field with the same id
 cascade_update = MyModel.exclude(id=sender.id).filter(some_key=sender.some_key)
 for c in cascade_update:
     c.some_field  = sender.some_field 
     c.save()
Run Code Online (Sandbox Code Playgroud)

Chr*_*att 6

在调用之前断开信号save,然后再重新连接:

post_save.disconnect(my_receiver_function, sender=MyModel)
instance.save()
post_save.connect(my_receiver_function, sender=MyModel)
Run Code Online (Sandbox Code Playgroud)


Cha*_*thk 5

断开信号连接并不是一个DRY一致的解决方案,例如使用 update() 而不是 save()。

要绕过模型上的信号触发,一种简单的方法是在当前实例上设置一个属性以防止即将发生的信号触发。

这可以使用一个简单的装饰器来完成,该装饰器检查给定实例是否具有“skip_signal”属性,如果有,则阻止调用该方法:

from functools import wraps

def skip_signal(signal_func):
    @wraps(signal_func)
    def _decorator(sender, instance, **kwargs):
        if hasattr(instance, 'skip_signal'):
            return None
        return signal_func(sender, instance, **kwargs)  
    return _decorator
Run Code Online (Sandbox Code Playgroud)

根据你的例子,这给了我们:

from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=MyModel)
@skip_signal()
def my_model_post_save(sender, instance, **kwargs):
    instance.some_field = my_value
    # Here we flag the instance with 'skip_signal'
    # and my_model_post_save won't be called again
    # thanks to our decorator, avoiding any signal recursion
    instance.skip_signal  = True
    instance.save()
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助。