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

tho*_*mad 8 python django django-signals django-orm m2m

我对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 )
Run Code Online (Sandbox Code Playgroud)

Chi*_*and 25

只需更新即可pk_set.你不需要做任何额外的工作.保存视频实例后,它将具有pk = 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])
Run Code Online (Sandbox Code Playgroud)

在上述方法中,只有在保存视频实例后才会保存类别.如果要在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()
Run Code Online (Sandbox Code Playgroud)

  • 有趣的是,有时会有一些小事情难倒你——当我测试这个时,我没有“pk=1”类别对象……所以,当它不起作用时,我认为我丢失了信号中的某些东西,因为它是我第一次和这些人一起工作时……事实上,我只是很傻,而且一开始就做对了。感谢您通过示例提供了非常清晰的答案。搞定了。 (2认同)