Merge pull request #642 from dcramer/patch-1

Send post_delete signals immediately
This commit is contained in:
Alex Gaynor 2013-01-14 13:48:31 -08:00
commit c346d358fd
3 changed files with 29 additions and 8 deletions

View File

@ -142,6 +142,7 @@ answer newbie questions, and generally made Django that much better:
crankycoder@gmail.com crankycoder@gmail.com
Paul Collier <paul@paul-collier.com> Paul Collier <paul@paul-collier.com>
Robert Coup Robert Coup
David Cramer <dcramer@gmail.com>
Pete Crosier <pete.crosier@gmail.com> Pete Crosier <pete.crosier@gmail.com>
Matt Croydon <http://www.postneo.com/> Matt Croydon <http://www.postneo.com/>
Jure Cuhalev <gandalf@owca.info> Jure Cuhalev <gandalf@owca.info>

View File

@ -75,7 +75,7 @@ class Collector(object):
self.using = using self.using = using
# Initially, {model: set([instances])}, later values become lists. # Initially, {model: set([instances])}, later values become lists.
self.data = {} self.data = {}
self.field_updates = {} # {model: {(field, value): set([instances])}} self.field_updates = {} # {model: {(field, value): set([instances])}}
# fast_deletes is a list of queryset-likes that can be deleted without # fast_deletes is a list of queryset-likes that can be deleted without
# fetching the objects into memory. # fetching the objects into memory.
self.fast_deletes = [] self.fast_deletes = []
@ -85,7 +85,7 @@ class Collector(object):
# should be included, as the dependencies exist only between actual # should be included, as the dependencies exist only between actual
# database tables; proxy models are represented here by their concrete # database tables; proxy models are represented here by their concrete
# parent. # parent.
self.dependencies = {} # {model: set([models])} self.dependencies = {} # {model: set([models])}
def add(self, objs, source=None, nullable=False, reverse_dependency=False): def add(self, objs, source=None, nullable=False, reverse_dependency=False):
""" """
@ -301,12 +301,11 @@ class Collector(object):
pk_list = [obj.pk for obj in instances] pk_list = [obj.pk for obj in instances]
query.delete_batch(pk_list, self.using) 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: if not model._meta.auto_created:
signals.post_delete.send( for obj in instances:
sender=model, instance=obj, using=self.using signals.post_delete.send(
) sender=model, instance=obj, using=self.using
)
# update collected instances # update collected instances
for model, instances_for_fieldvalues in six.iteritems(self.field_updates): for model, instances_for_fieldvalues in six.iteritems(self.field_updates):

View File

@ -229,6 +229,27 @@ class DeletionTests(TestCase):
models.signals.post_delete.disconnect(log_post_delete) models.signals.post_delete.disconnect(log_post_delete)
models.signals.post_delete.disconnect(log_pre_delete) models.signals.post_delete.disconnect(log_pre_delete)
def test_relational_post_delete_signals_happen_before_parent_object(self):
deletions = []
def log_post_delete(instance, **kwargs):
self.assertTrue(R.objects.filter(pk=instance.r_id))
self.assertEquals(type(instance), S)
deletions.append(instance.id)
r = R.objects.create(pk=1)
S.objects.create(pk=1, r=r)
models.signals.post_delete.connect(log_post_delete, sender=S)
try:
r.delete()
finally:
models.signals.post_delete.disconnect(log_post_delete)
self.assertEquals(len(deletions), 1)
self.assertEquals(deletions[0], 1)
@skipUnlessDBFeature("can_defer_constraint_checks") @skipUnlessDBFeature("can_defer_constraint_checks")
def test_can_defer_constraint_checks(self): def test_can_defer_constraint_checks(self):
u = User.objects.create( u = User.objects.create(