mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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.
This commit is contained in:
		| @@ -75,7 +75,7 @@ class Collector(object): | ||||
|         self.using = using | ||||
|         # Initially, {model: set([instances])}, later values become lists. | ||||
|         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 | ||||
|         # fetching the objects into memory. | ||||
|         self.fast_deletes = [] | ||||
| @@ -85,7 +85,7 @@ class Collector(object): | ||||
|         # should be included, as the dependencies exist only between actual | ||||
|         # database tables; proxy models are represented here by their concrete | ||||
|         # parent. | ||||
|         self.dependencies = {} # {model: set([models])} | ||||
|         self.dependencies = {}  # {model: set([models])} | ||||
|  | ||||
|     def add(self, objs, source=None, nullable=False, reverse_dependency=False): | ||||
|         """ | ||||
| @@ -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): | ||||
|   | ||||
| @@ -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( | ||||
|   | ||||
		Reference in New Issue
	
	Block a user