我希望在多对多关系发生变化时触发某些行为,但我不确定哪种信号设置最适合捕获由于删除关系的一侧而导致的关系变化。在这种情况下m2m_changed
似乎没有触发,常规post_save
和post_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_remove
或post_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
信号将会终止。然而正如我在顶部说的那样,我觉得我错过了必要的东西吗?