在model_save之后更新M2M值

时间:2016-03-03 23:08:30

标签: python django django-models django-forms

我有一个名为Contact的模型,它具有称为标签的M2M关系。该模型有两个booleanfields(在本例中为student,alumus和employee)。

我想实现以下目标: 每次保存Contact对象后,我想检查每个booleanfield是否存在标记关系。如果它不存在,则应该添加它。

我认为这适用于post_save挂钩,这是我的代码:

models.py

class Contact(BaseModel):
    title = models.CharField(max_length=30, blank=True)
    student = models.BooleanField(default=False)
    alumnus = models.BooleanField(default=False)
    employee = models.BooleanField(default=False)
    tags = models.ManyToManyField(Tag)

def update_tag(instance, tag_name, tagged):
    tag, created = Tag.objects.get_or_create(name=tag_name, defaults={'deletable': False})
    if tagged:
        instance.tags.add(tag)
    else:
        instance.tags.remove(tag)

@receiver(post_save, sender=Contact, dispatch_uid="update_tags")
def update_tags(sender, instance, **kwargs):
    update_tag(instance, "Alumni", instance.alumnus)
    update_tag(instance, "Students", instance.student)
    update_tag(instance, "Employees", instance.employee)

但是我注意到这只有在我不在ModelForm对象中包含我的标记字段时才有效。如果包含,则忽略所有更新。如果没有包含,一切都按预期工作。

我做了一些研究,found显然m2m关系完全不同:

  

当您通过管理表单保存模型时,它不是原子事务。   主要对象首先被保存(以确保它有PK),然后是   M2M被清除,新值设置为出现的任何值   形成。因此,如果您在主要对象的save()中,那么您就在   M2M还没有更新的机会之窗。事实上,   如果你试图对M2M做一些事情,那么改变就会消失   通过clear()。

但是,由于我没有使用管理员表单,我不明白为什么在我的情况下也会出现这种情况。有谁知道如何解决我的问题?

1 个答案:

答案 0 :(得分:0)

这不仅仅是在管理表单中,当你在任何地方保存任何Django模型时都会发生这种情况。

我没有找到任何关于“为什么”的良好文档链接,但我认为它与数据库结构有关。在Django中,它存储在单个模型中,但在数据库级别上,它创建了ContactTag之间的中间表(这是在数据库级别上执行它的正确方法) - 它只是隐藏在在Django里面。

您需要使用m2m_changed信号,而不是使用post_save信号,当更改ManyToMany字段时,该信号将会触发。

相关问题