使用Django的m2m_changed在pre_add时修改保存内容

17 投票
1 回答
20623 浏览
提问于 2025-04-28 20:44

我对Django的信号机制不是很熟悉,需要一些帮助。

我该如何在实例保存之前修改pk_set?我需要返回一些东西给信号的调用者吗(比如kwargs)?还是说我自己来保存instance

举个简单的例子:我想确保所有保存的视频都包含类别pk=1。我该如何使用m2m_changed来实现这个?

class Video(models.Model):
    category = models.ManyToManyField('Category')

def video_category_changed(sender, **kwargs):
    action = kwargs.pop('action', None)
    pk_set = kwargs.pop('pk_set', None)
    instance = kwargs.pop('instance', None)

    if action == "pre_add":
        if 1 not in pk_set:
            pk_set.update( [ 1 ] )  # adding this to the set
            # do something else?
            # profit?

m2m_changed.connect( video_category_changed, sender=Video.category.through )
暂无标签

1 个回答

50

只需要更新一下 pk_set 就可以了,没必要做其他的工作。一旦视频实例被保存,它就会有一个类别,类别的编号是1。

from django.db import models
from django.db.models.signals import m2m_changed
from django.dispatch import receiver

class Category(models.Model):
    pass

class Video(models.Model):
    category = models.ManyToManyField('Category')

@receiver(m2m_changed, sender=Video.category.through)
def video_category_changed(sender, **kwargs):
    action = kwargs.pop('action', None)
    pk_set = kwargs.pop('pk_set', None)    
    if action == "pre_add":
        if 1 not in pk_set:
            pk_set.update([1])

在上面的方法中,类别只有在视频实例被保存后才会被保存。如果你想在 m2m_changed 实例中明确地保存它们,也可以这样做。

@receiver(m2m_changed, sender=Video.category.through)
def video_category_changed(sender, **kwargs):
    instance = kwargs.pop('instance', None)
    pk_set = kwargs.pop('pk_set', None)
    action = kwargs.pop('action', None)
    if action == "pre_add":
        if 1 not in pk_set:
            c = Category.objects.get(pk=1)
            instance.category.add(c)
            instance.save()

撰写回答