情况如下:
假设我在django中有一个模型A.当我保存一个对象(A类)时,我需要将它的字段保存到该类的所有其他对象中。我的意思是我需要每个其他A对象都是lat保存的副本。
当我使用信号(例如后保存)时,我得到一个递归(对象试图相互保存,我猜)并且我的python死了。
我是男性我希望在保存前/后信号中对同一个类使用.save()方法会导致递归但只是不知道如何避免它。
我们做什么?
答案 0 :(得分:7)
@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()
希望这有帮助。
答案 1 :(得分:5)
这将有效:
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()
如果你有很多字段,你可能希望在将它们复制到另一个模型时迭代它们。我会留给你的。
答案 2 :(得分:5)
另一种处理方法是在保存时删除监听器。所以:
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)