在处理M2M字段时,很多人会遇到这样一个坑。
例如,我们打算在对象修改时,触发一些动作。常规的做法就是重载模型的 save()
方法。
举例说明, ElectricStatus
模型中有个devices
的多对多字段。
我们patch了数据
{
"devices": [
17
]
}
但在 ElectricStatus
模型的 save()
方法中,self.devices.all()
并没有17,即便是重新获取
def save(self, *args, **kwargs):
super().save(*args, **kwargs)
new_instance = ElectricStatus.objects.get(pk=self.pk)
# 仍然没有17的存在
print(new_instance.devices.all())
看来,Django在保存模型时,还没有开始更新m2m字段。所以,用 save()
方法是不可行的。
仔细想想也对,m2m字段其实暗含了另一个隐藏模型,它在这里对应的是electricstatus_devices
表。如果 ElectricStatus
的对象还没有保存,那么electricstatus_devices
并不会知道这个对象的id,根本无法完成更新。
所以,Django只能先保存ElectricStatus
的对象,然后再更新electricstatus_devices
表。这就能解释前面的疑惑了。
为了实现一开始的需求,Django提供了m2m_changed
信号,也就是在electricstatus_devices
模型变动时,能够触发这个信号,让我们有机会去hook一些动作。
如果用的是django admin,那么可以用save_related
来hook;如果用的是 django restframework
,还可以用重载 perform_update
方法来hook。
网友评论