[Django] 多对多Many-to-Many 字段的特殊处理

2022-04-27  本文已影响0人  alue

在处理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。

上一篇 下一篇

猜你喜欢

热点阅读