model_save 后更新 M2M 值
Update M2M value after model_save
我有一个名为 Contact 的模型,它具有称为标签的 M2M 关系。该模型有几个布尔字段(在本例中为学生、校友和员工)。
我想实现以下目标:
每次保存联系人对象后,我想检查每个布尔字段是否存在标签关系。如果不存在,应该添加。
我认为这可以与 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 关系非常不同:
When you save a model via admin forms it's not an atomic transaction.
The main object gets saved first (to make sure it has a PK), then the
M2M is cleared and the new values set to whatever came out of the
form. So if you are in the save() of the main object you are in a
window of opportunity where the M2M hasn't been updated yet. In fact,
if you try to do something to the M2M, the change will get wiped out
by the clear().
但是,由于我没有使用管理表单,所以我不明白为什么我的情况也会出现这种情况。有人知道如何解决我的问题吗?
不仅在管理表单中,当您在任何地方保存任何 Django 模型时都会发生这种情况。
我没有找到指向 "why" 的任何好的文档链接,但我相信它与数据库结构有关。在 Django 中,它存储在单个模型中,但在数据库级别,它在 Contact
和 Tag
之间创建一个中间 table (这是在数据库级别执行此操作的正确方法)-它只是隐藏在 Django 中。
您需要使用 m2m_changed 信号而不是使用 post_save
信号,它会在 ManyToMany 字段更改时触发。
我有一个名为 Contact 的模型,它具有称为标签的 M2M 关系。该模型有几个布尔字段(在本例中为学生、校友和员工)。
我想实现以下目标: 每次保存联系人对象后,我想检查每个布尔字段是否存在标签关系。如果不存在,应该添加。
我认为这可以与 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 关系非常不同:
When you save a model via admin forms it's not an atomic transaction. The main object gets saved first (to make sure it has a PK), then the M2M is cleared and the new values set to whatever came out of the form. So if you are in the save() of the main object you are in a window of opportunity where the M2M hasn't been updated yet. In fact, if you try to do something to the M2M, the change will get wiped out by the clear().
但是,由于我没有使用管理表单,所以我不明白为什么我的情况也会出现这种情况。有人知道如何解决我的问题吗?
不仅在管理表单中,当您在任何地方保存任何 Django 模型时都会发生这种情况。
我没有找到指向 "why" 的任何好的文档链接,但我相信它与数据库结构有关。在 Django 中,它存储在单个模型中,但在数据库级别,它在 Contact
和 Tag
之间创建一个中间 table (这是在数据库级别执行此操作的正确方法)-它只是隐藏在 Django 中。
您需要使用 m2m_changed 信号而不是使用 post_save
信号,它会在 ManyToMany 字段更改时触发。