创建对象时防止 m2m_changed 触发

2023-12-25

当使用 Django 信号时,例如post_save您可以通过执行以下操作来防止它在首次创建对象时触发:

@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 关系是在项目最初创建后应用的,所以没有传入这样的参数 https://docs.djangoproject.com/en/1.8/ref/signals/#m2m-changed,在这些情况下很难抑制。

@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当它在刚刚创建的对象上完成时发出信号?


我认为没有简单的方法可以做到这一点。

As the Django 文档 https://docs.djangoproject.com/en/1.8/topics/db/examples/many_to_many/也就是说,在保存项目之前,您无法将其与关系关联起来。文档中的示例:

>>> 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)

从逻辑上讲,关系记录不可能在没有外部信息的情况下知道它是否被添加到“刚刚创建的项目”或“已经存在一段时间的项目”。

我想出的一些解决方法:

解决方案1.添加一个DatetimeFieldMyModel来指示创建时间。 m2m_changed 处理程序使用创建时间来检查项目的创建时间。在某些情况下确实有效,但不能保证正确性

解决方案 2. 在中添加 'created' 属性MyModel,无论是在 post_save 处理程序中还是在其他代码中。例子:

@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

Demo:

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实例,而不是保存在数据库中,所以事情可能会出错:

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 :)

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

创建对象时防止 m2m_changed 触发 的相关文章

随机推荐