我想在很多关系发生变化时触发一些行为,但我不确定什么信号设置最适合捕捉由于删除关系的一方而产生的对这种关系的改变。在这种情况下,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模型的一个实例:
# 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信号终究会触发。然而,正如我在顶部所说的,我好像错过了一些这是必要的东西?
发布于 2017-10-17 22:44:36
在发布我的问题时,我忽略了这一点,但这似乎是Django https://code.djangoproject.com/ticket/17688中的一个开放bug。
https://stackoverflow.com/questions/46782056
复制相似问题