#33505: Inconsistent Behavior with Abstract Models and Signals
-------------------------------------+-------------------------------------
               Reporter:  Ken        |          Owner:  nobody
  Weaver                             |
                   Type:  Bug        |         Status:  new
              Component:  Database   |        Version:  3.2
  layer (models, ORM)                |
               Severity:  Normal     |       Keywords:
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 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
 }}}

-- 
Ticket URL: <https://code.djangoproject.com/ticket/33505>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/053.ef679f62928e994a1ce7b265182f25d6%40djangoproject.com.

Reply via email to