這種情況:django:使用後保存信號遞歸
假設我在django中有一個模型A.當我保存一個對象(類A)時,我需要將它的字段保存到此類的所有其他對象中。我的意思是我需要其他所有的對象都是保存副本。
當我使用信號(例如保存後),我得到一個遞歸(對象試圖保存對方,我猜)和我的python死亡。
我希望在保存前/保存信號的同一類中使用.save()方法會導致遞歸,但不知道如何避免它。
我們該怎麼辦?
這種情況:django:使用後保存信號遞歸
假設我在django中有一個模型A.當我保存一個對象(類A)時,我需要將它的字段保存到此類的所有其他對象中。我的意思是我需要其他所有的對象都是保存副本。
當我使用信號(例如保存後),我得到一個遞歸(對象試圖保存對方,我猜)和我的python死亡。
我希望在保存前/保存信號的同一類中使用.save()方法會導致遞歸,但不知道如何避免它。
我們該怎麼辦?
這將工作:
class YourModel(models.Model):
name = models.CharField(max_length=50)
def save_dupe(self):
super(YourModel, self).save()
def save(self, *args, **kwargs):
super(YourModel, self).save(*args, **kwargs)
for model in YourModel.objects.exclude(pk=self.pk):
model.name = self.name
# Repeat the above for all your other fields
model.save_dupe()
如果你有很多領域,你可能會想將它們複製到其他模型時,在它們之間迭代。我會把它留給你。
當保存的模型是用戶和AFAIK時,它會發生什麼情況,對它進行子類化並不是一個好主意。比方說,我有一個post_save函數與發件人作爲用戶,並在該功能我想更新實例。再次調用save會觸發post_save並停止本地服務器。 – Marconi 2011-02-27 08:57:53
更好的是,不是'model.save_dupe()'而是'super(YourModel,model).save()'。 – 2013-08-20 17:22:52
處理此問題的另一種方法是在保存時刪除偵聽器。所以:
class Foo(models.Model):
...
def foo_post_save(instance):
post_save.disconnect(foo_post_save, sender=Foo)
do_stuff_toSaved_instance(instance)
instance.save()
post_save.connect(foo_post_save, sender=Foo)
post_save.connect(foo_post_save, sender=Foo)
你救了我的一天,謝謝! – 2014-01-29 11:59:44
@ShawnFumo斷開信號是危險的,如果同樣的模型在同一時間保存在別處,不這樣做!
@Aram Dulyan,您的解決方案有效,但阻止您使用如此強大的信號!
如果您想避免遞歸併繼續使用signals(),一個簡單的方法是在當前實例上設置一個屬性,以防止即將發生的信號觸發。
這可以用一個簡單的裝飾來檢查,如果給定的實例具有「skip_signal」屬性來完成,如果是防止被調用的方法:
from functools import wraps
def skip_signal():
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
return _skip_signal
現在,我們可以用它這個方式:
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):
# you processing
pass
m = MyModel()
# Here we flag the instance with 'skip_signal'
# and my_model_post_save won't be called
# thanks to our decorator, avoiding any signal recursion
m.skip_signal = True
m.save()
希望這會有所幫助。
保存後請勿忘記'del skip_signal'。 – 2014-12-17 11:29:12
也許添加一些代碼讓你的情況變得更清晰了? – adamk 2010-07-14 14:17:42
如果您使用pre_save,將不會發生,因爲您不必自己調用save(),它會在«自然»發生。 – 2014-12-17 11:33:12