diff --git a/django/db/models/base.py b/django/db/models/base.py index 458499c722..70420300e4 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -395,6 +395,21 @@ class Model(object): for sub_obj in getattr(self, rel_opts_name).all(): sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null) + # Handle any ancestors (for the model-inheritance case). We do this by + # traversing to the most remote parent classes -- those with no parents + # themselves -- and then adding those instances to the collection. That + # will include all the child instances down to "self". + parent_stack = self._meta.parents.values() + while parent_stack: + link = parent_stack.pop() + parent_obj = getattr(self, link.name) + if parent_obj._meta.parents: + parent_stack.extend(parent_obj._meta.parents.values()) + continue + # At this point, parent_obj is base class (no ancestor models). So + # delete it and all its descendents. + parent_obj._collect_sub_objects(seen_objs) + def delete(self): assert self._get_pk_val() is not None, "%s object can't be deleted because its %s attribute is set to None." % (self._meta.object_name, self._meta.pk.attname) diff --git a/tests/regressiontests/model_inheritance_regress/models.py b/tests/regressiontests/model_inheritance_regress/models.py index 33e2e0e4f6..24d6186150 100644 --- a/tests/regressiontests/model_inheritance_regress/models.py +++ b/tests/regressiontests/model_inheritance_regress/models.py @@ -131,4 +131,26 @@ __test__ = {'API_TESTS':""" >>> Child.objects.dates('created', 'month') [datetime.datetime(2008, 6, 1, 0, 0)] +# Regression test for #7276: calling delete() on a model with multi-table +# inheritance should delete the associated rows from any ancestor tables, as +# well as any descendent objects. + +>>> ident = ItalianRestaurant.objects.all()[0].id +>>> Place.objects.get(pk=ident) + +>>> xx = Restaurant.objects.create(name='a', address='xx', serves_hot_dogs=True, serves_pizza=False) + +# This should delete both Restuarants, plus the related places, plus the ItalianRestaurant. +>>> Restaurant.objects.all().delete() + +>>> Place.objects.get(pk=ident) +Traceback (most recent call last): +... +DoesNotExist: Place matching query does not exist. + +>>> ItalianRestaurant.objects.get(pk=ident) +Traceback (most recent call last): +... +DoesNotExist: ItalianRestaurant matching query does not exist. + """}