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

Posted

技术标签:

【中文标题】使用 Django 的 m2m_changed 修改正在保存的内容 pre_add【英文标题】:Using Django's m2m_changed to modify what is being saved pre_add 【发布时间】:2014-12-17 01:33:23 【问题描述】:

我对 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】:

只需更新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])

在上述方法中,只有在视频实例保存后才会保存类别。如果您想明确地将它们保存在 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()

【讨论】:

有趣的是,有时小事情会难倒你——我在测试这个时没有pk=1 类别对象......所以,当它不起作用时,我以为我错过了与信号有关的东西,因为这是我第一次与那些人一起工作……事实上,我只是很傻,一开始就做对了。感谢您通过示例提供非常明确的答案。搞定了。

以上是关于使用 Django 的 m2m_changed 修改正在保存的内容 pre_add的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Django 中使 m2m_changed 信号原子化?

在 Django 中更新多对多关系时如何不触发“m2m_changed”信号?

删除关系时,Django Python m2m_change 不起作用

GenericRelation 的 Django m2m_changed 信号,有可能吗?

django的内置信号

当 m2m_changed 调用“pre_clear”时如何访问 pk_set?