Django save方法不立即更新ManyToManyField的问题

在Django中重写model的save方法,在save方法中先保存self数据,但是立即获取self的ManyToManyField依旧为未更新之前的ManyToManyField内容,只有下次更新的时候才能获取到上次更新时的ManyToManyField字段内容。这是由于在save之后立即调用self的ManyToManyField字段,但是ManyToManyField的数据库通讯还没有完成,所以获取到的是之前的ManyToManyField字段内容,我们需要监听数据库通讯过程,等待通讯完成再去获取更新完成的ManyToManyField内的字段内容。

具体方法:在Django 1.9之后提供了transaction工具来监听数据库通讯过程,文档见performing-actions-after-commit,在1.9之前可以使用django-transaction-hooks来监听数据库通讯过程。

实例代码(category为ManyToManyField对应的字段):

from django.db import transaction

class Goods(models.Model):
    .
    .
    .
    def save(self, *args, **kwargs):
        # 先保存商品条目
        instance = super(Goods, self).save(*args, **kwargs)
        print(self.unit)
        # 调用transaction.on_commit监听数据库通讯执行完成
        # update_content方法不可以变成update_content()
        transaction.on_commit(self.update_content)
        return instance

    def update_content(self):
        # 此时获得的self.category.all()为更新后的数据集合
        for category in self.category.all():
            print(category.__str__())
            Content.objects.get_or_create(goods=self, category=category)

方法二是使用signal来监听m2m字段变化,示例如下:

from django.db.models.signals import m2m_changed
@receiver(m2m_changed, sender=Person.friends.through)
def friends_change(sender, action, pk_set, instance=None, **kwargs):
    if action in ['post_add', 'post_remove']:
        queryset = instance.friends.all()
        for friend in queryset:
            print(friend.__str__())