Fixed #7276 -- Delete multi-table objects correctly.

When model inheritance is used, the parent objects should be deleted as part of
the delete() call on the child.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@7784 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Malcolm Tredinnick 2008-06-29 09:41:35 +00:00
parent 2c1d6a80b3
commit 4931639636
2 changed files with 37 additions and 0 deletions

View File

@ -395,6 +395,21 @@ class Model(object):
for sub_obj in getattr(self, rel_opts_name).all(): for sub_obj in getattr(self, rel_opts_name).all():
sub_obj._collect_sub_objects(seen_objs, self.__class__, related.field.null) 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): 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) 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)

View File

@ -131,4 +131,26 @@ __test__ = {'API_TESTS':"""
>>> Child.objects.dates('created', 'month') >>> Child.objects.dates('created', 'month')
[datetime.datetime(2008, 6, 1, 0, 0)] [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)
<Place: Guido's All New House of Pasta the place>
>>> 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.
"""} """}