Django:当删除多对多的一边时,没有m2m_changed信号?

时间:2017-10-17 03:32:52

标签: django django-signals manytomanyfield

我希望在多对多关系发生变化时触发某些行为,但我不确定哪种信号设置最适合捕获由于删除关系的一侧而导致的关系变化。在这种情况下m2m_changed似乎没有触发,常规post_savepost_delete信号似乎也不适用于through模型?

我目前的解决方案是在构成关系两侧的模型上听取pre_delete,然后清除该信号中的关系以触发m2m_changed。我很惊讶我必须这样做,并且觉得我有些不对劲。

我在这里缺少什么?如果我没有遗漏任何原因,为什么这是必要的(即为什么默认情况下不会发出这样的信号)?

代码示例:

class ResearchField(models.Model):

    name = models.CharField(unique=True, max_length=200)

class Researcher(models.Model):

    name = models.CharField(max_length=200)
    research_fields = models.ManyToManyField(ResearchField, blank=True)

@receiver(m2m_changed, sender=Researcher.research_fields.through)
def research_fields_changed(sender, instance, action, **kwargs):
    # need to do something important here
    print('m2m_changed', action)

volcanology = ResearchField.objects.create(name='Volcanology')
researcher = Researcher.objects.create(name='A. Volcanologist')

researcher.research_fields.add(volcanology)
>>> m2m_changed pre_add
>>> m2m_changed post_add

当从任何一方移除关系时,此m2m_changed信号会按预期触发:

researcher.research_fields.remove(volcanology)
# or equally volcanology.researcher_set.remove(researcher)
>>> m2m_changed pre_remove
>>> m2m_changed post_remove

但是,如果我只是删除关系的一边,则不会发出pre_removepost_remove m2m_changed信号,尽管Django delete输出指示through的实例1}}模型已删除:

# with the relationship intact
volcanology.delete()
>>> (2, {'ResearchField': 1, 'Researcher_research_fields': 1})

此时我尝试了:

@receiver(post_delete, sender=Researcher.research_fields.through)
def through_model_deleted(sender, instance, **kwargs):
    print('through model deleted')

但这永远不会开火?

因此,我目前的解决方案是:

@receiver(pre_delete, sender=ResearchField)
def research_field_deleted(sender, instance, **kwargs):
    instance.researcher_set.clear()

要自定义强制执行,当通过已删除的Researcher.research_fields.through级联删除ResearchField个对象时,m2m_changed信号将会终止。然而正如我在顶部说的那样,我觉得我错过了必要的东西吗?

1 个答案:

答案 0 :(得分:0)

我在发布问题时错过了这个,但似乎这是Django https://code.djangoproject.com/ticket/17688中的一个漏洞。