Commit 272de9eb authored by David Cramer's avatar David Cramer
Browse files

Send post_delete signals immediately

In a normal relational construct, if you're listening for an event
that signals a child was deleted, you dont expect that the parent
was deleted already.

This change ensures that post_delete signals are fired immediately
after objects are deleted in the graph.
parent 4720117a
Loading
Loading
Loading
Loading
+12 −10
Original line number Diff line number Diff line
@@ -262,6 +262,14 @@ class Collector(object):
        self.data = SortedDict([(model, self.data[model])
                                for model in sorted_models])

    def send_post_delete_signals(self, model, instances):
        if model._meta.auto_created:
            return
        for obj in instances:
            signals.post_delete.send(
                sender=model, instance=obj, using=self.using
            )

    @force_managed
    def delete(self):
        # sort instance collections
@@ -300,13 +308,7 @@ class Collector(object):
            query = sql.DeleteQuery(model)
            pk_list = [obj.pk for obj in instances]
            query.delete_batch(pk_list, self.using)

        # send post_delete signals
        for model, obj in self.instances_with_model():
            if not model._meta.auto_created:
                signals.post_delete.send(
                    sender=model, instance=obj, using=self.using
                )
            self.send_post_delete_signals(model, instances)

        # update collected instances
        for model, instances_for_fieldvalues in six.iteritems(self.field_updates):
+12 −0
Original line number Diff line number Diff line
@@ -229,6 +229,18 @@ class DeletionTests(TestCase):
        models.signals.post_delete.disconnect(log_post_delete)
        models.signals.post_delete.disconnect(log_pre_delete)

    def test_relational_post_delete_signals_happen_before_parent_object(self):
        def log_post_delete(instance, **kwargs):
            self.assertTrue(R.objects.filter(pk=instance.r_id))

        models.signals.post_delete.connect(log_post_delete, sender=S)

        r = R.objects.create(pk=1)
        S.objects.create(pk=1, r=r)
        r.delete()

        models.signals.post_delete.disconnect(log_post_delete)

    @skipUnlessDBFeature("can_defer_constraint_checks")
    def test_can_defer_constraint_checks(self):
        u = User.objects.create(