﻿id	summary	reporter	owner	description	type	status	component	version	severity	resolution	keywords	cc	stage	has_patch	needs_docs	needs_tests	needs_better_patch	easy	ui_ux
33505	Inconsistent Behavior with Abstract Models and Signals	Ken Weaver	nobody	"Recently we came across an issue with abstract models and signals, specifically many to many signals. It seems that for most signals, models that have inherited from an abstract class (or perhaps any class) will not also inherit the signals of that class. This is not unexpected. However, for `m2m_changed` signals, the signal '''fires for every many to many change in the entire application'''. I have created a minimum (ish) working example [https://github.com/kenjones21/django_signal_bug here], and I will paste the relevant code below as well.

I think ideally django would stop you from binding signals to abstract models if they can't ever work, or spat out a warning when it was attempted. If that isn't possible, never firing the signal would be preferable to always firing the signal; the latter is highly likely to break parts of your application you weren't testing. 

Admittedly, I don't think the documentation ever specifies what the behavior should be related to abstract/inherited models and signals. If none of the changes here are possible, I think a warning in the documentation on the model page, the signals page, or both would be helpful, and I would be more than happy to work on that.

{{{
class Related(models.Model):
    pass

class Abstract(models.Model):
    m2m_field = models.ManyToManyField(to=Related)
    int_field = models.IntegerField(default=0)
    class Meta:
        abstract = True

class OtherRelated(models.Model):
    pass

class Other(models.Model):
    m2m_field = models.ManyToManyField(to=OtherRelated)

@receiver(m2m_changed, sender=Abstract.m2m_field.through)
def abstract_m2m_signal(sender, **kwargs):
    wrapped_abstract_m2m(sender, **kwargs)
}}}
{{{
    @patch('app.models.wrapped_abstract_m2m', side_effect=mock_signal)
    def test_abstract_m2m_signal_not_called(self, signal_mock):
        other = Other.objects.create()
        related = OtherRelated.objects.create()
        other.m2m_field.add(related)
        self.assertEqual(signal_mock.call_count, 0) # this fails
}}}"	Bug	closed	Database layer (models, ORM)	3.2	Normal	invalid			Unreviewed	0	0	0	0	0	0
