创建对象时防止触发m2m_changed [英] Prevent m2m_changed from firing when creating an object
问题描述
使用诸如 post_save
之类的Django信号时,您可以通过执行以下操作来防止它在首次创建对象时触发:
When using a Django signal like post_save
you can prevent it from firing when an object is first created by doing something like:
@receiver(post_save,sender=MyModel)
def my_signal(sender, instance, created,**kwargs):
if not created:
pass # Do nothing, as the item is new.
else:
logger.INFO("The item changed - %s"%(instance) )
但是,最初创建项目后,会应用ManyToMany关系,因此没有传入这样的参数,因此在这种情况下很难隐瞒.
However, ManyToMany relations are applied after an item is initially created, so no such argument is passed in, making it difficult to suppress in these cases.
@receiver(m2m_changed,sender=MyModel.somerelation.though)
def my_signal(sender, instance, created,**kwargs):
if __something__: # What goes here?
pass # Do nothing, as the item is new.
else:
logger.INFO("The item changed - %s"%(instance) )
在刚刚创建的对象上执行 m2m_changed
信号时,是否有一种简便的方法来抑制它?
Is there an easy way to suppress an m2m_changed
signal when its being done on an object that has just been created?
推荐答案
我认为没有简单的方法可以做到这一点.
I think there is no easy way to do that.
正如 Django文档所述,您可以't将一个项目与一个关系相关联,直到将其保存.文档中的示例:
As the Django doc says, you can't associate an item with a relation until it's been saved. Example from the doc:
>>> a1 = Article(headline='...')
>>> a1.publications.add(p1)
Traceback (most recent call last):
...
ValueError: 'Article' instance needs to have a primary key value before a many-to-many relationship can be used.
# should save Article first
>>> a1.save()
# the below statement never know it's just following a creation or not
>>> a1.publications.add(p1)
在没有外部信息的情况下,关系记录在逻辑上不可能知道是将其添加到刚刚创建的项目"还是已经存在一段时间的项目".
It's logically not possible for a relation record to know whether it is added to "a just created item" or "an item that already exists for some time", without external info.
我想出了一些解决方法:
Some workarounds I came up with:
解决方案1.在 MyModel
中添加DatetimeField以指示创建时间.m2m_changed处理程序使用创建时间来检查何时创建该项目.它在某些情况下可以实际使用,但不能保证正确性
Solution 1. add a DatetimeField in MyModel
to indicate creation time. m2m_changed handler uses the creation time to check when is the item created. It work practically in some cases, but cannot guarantee correctness
解决方案2.在post_save处理程序或其他代码中的 MyModel
中添加一个"created"属性.示例:
Solution 2. add a 'created' attribute in MyModel
, either in a post_save handler or in other codes. Example:
@receiver(post_save, sender=Pizza)
def pizza_listener(sender, instance, created, **kwargs):
instance.created = created
@receiver(m2m_changed, sender=Pizza.toppings.through)
def topping_listener(sender, instance, action, **kwargs):
if action != 'post_add':
# as example, only handle post_add action here
return
if getattr(instance, 'created', False):
print 'toppings added to freshly created Pizza'
else:
print 'toppings added to modified Pizza'
instance.created = False
演示:
p1 = Pizza.objects.create(name='Pizza1')
p1.toppings.add(Topping.objects.create())
>>> toppings added to freshly created Pizza
p1.toppings.add(Topping.objects.create())
>>> toppings added to modified Pizza
p2 = Pizza.objects.create(name='Pizza2')
p2.name = 'Pizza2-1'
p2.save()
p2.toppings.add(Topping.objects.create())
>>> toppings added to modified Pizza
但是请小心使用此解决方案.由于'created'属性已分配给Python实例,而不是保存在数据库中,因此出现以下情况可能会出错:
But be careful using this solution. Since 'created' attribute was assigned to Python instance, not saved in DB, things can go wrong as:
p3 = Pizza.objects.create(name='Pizza3')
p3_1 = Pizza.objects.get(name='Pizza3')
p3_1.toppings.add(Topping.objects.create())
>>> toppings added to modified Pizza
p3.toppings.add(Topping.objects.create())
>>> toppings added to freshly created Pizza
这就是答案.然后,在这里抓到你了!我是github django-notifications组的zhang-z:)
That's all about the answer. Then, caught you here! I'm zhang-z from github django-notifications group :)
这篇关于创建对象时防止触发m2m_changed的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!