创建对象时防止触发m2m_changed [英] Prevent m2m_changed from firing when creating an object

查看:65
本文介绍了创建对象时防止触发m2m_changed的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用诸如 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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆