我有一个名为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()。
但是,由于我没有使用管理员表单,我不明白为什么在我的情况下也会出现这种情况。有谁知道如何解决我的问题?
答案 0 :(得分:0)
这不仅仅是在管理表单中,当你在任何地方保存任何Django模型时都会发生这种情况。
我没有找到任何关于“为什么”的良好文档链接,但我认为它与数据库结构有关。在Django中,它存储在单个模型中,但在数据库级别上,它创建了Contact
和Tag
之间的中间表(这是在数据库级别上执行它的正确方法) - 它只是隐藏在在Django里面。
您需要使用m2m_changed信号,而不是使用post_save
信号,当更改ManyToMany字段时,该信号将会触发。