1
0
mirror of https://github.com/django/django.git synced 2025-06-08 21:19:13 +00:00

magic-removal: Fixed problem with delete where dependent objects would be deleted in the incorrect order due to a fragile sort algorithm. Thanks to Luke Plant and Malcolm Tredinnick for helping to track this one down.

git-svn-id: http://code.djangoproject.com/svn/django/branches/magic-removal@2487 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Russell Keith-Magee 2006-03-04 12:13:41 +00:00
parent 3a1cc65322
commit fdd1e3682f
3 changed files with 16 additions and 24 deletions

View File

@ -10,6 +10,7 @@ from django.db.models import signals
from django.db.models.loading import register_models from django.db.models.loading import register_models
from django.dispatch import dispatcher from django.dispatch import dispatcher
from django.core.exceptions import ObjectDoesNotExist from django.core.exceptions import ObjectDoesNotExist
from django.utils.datastructures import SortedDict
from django.utils.functional import curry from django.utils.functional import curry
from django.conf import settings from django.conf import settings
import re import re
@ -220,7 +221,7 @@ class Model(object):
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)
# Find all the objects than need to be deleted # Find all the objects than need to be deleted
seen_objs = {} seen_objs = SortedDict()
self._collect_sub_objects(seen_objs) self._collect_sub_objects(seen_objs)
# Actually delete the objects # Actually delete the objects

View File

@ -234,7 +234,7 @@ class QuerySet(object):
# Collect all the objects to be deleted, and all the objects that are related to # Collect all the objects to be deleted, and all the objects that are related to
# the objects that are to be deleted # the objects that are to be deleted
seen_objs = {} seen_objs = SortedDict()
for object in del_query: for object in del_query:
object._collect_sub_objects(seen_objs) object._collect_sub_objects(seen_objs)
@ -815,21 +815,10 @@ def lookup_inner(path, clause, value, opts, table, column):
return tables, joins, where, params return tables, joins, where, params
def compare_models(x, y):
"Comparator for Models that puts models in an order where dependencies are easily resolved."
for field in x._meta.fields:
if field.rel and not field.null and field.rel.to == y:
return -1
for field in y._meta.fields:
if field.rel and not field.null and field.rel.to == x:
return 1
return 0
def delete_objects(seen_objs): def delete_objects(seen_objs):
"Iterate through a list of seen classes, and remove any instances that are referred to" "Iterate through a list of seen classes, and remove any instances that are referred to"
seen_classes = set(seen_objs.keys()) ordered_classes = seen_objs.keys()
ordered_classes = list(seen_classes) ordered_classes.reverse()
ordered_classes.sort(compare_models)
cursor = connection.cursor() cursor = connection.cursor()
@ -855,7 +844,7 @@ def delete_objects(seen_objs):
','.join(['%s' for pk in pk_list])), ','.join(['%s' for pk in pk_list])),
pk_list) pk_list)
for field in cls._meta.fields: for field in cls._meta.fields:
if field.rel and field.null and field.rel.to in seen_classes: if field.rel and field.null and field.rel.to in seen_objs:
cursor.execute("UPDATE %s SET %s=NULL WHERE %s IN (%s)" % \ cursor.execute("UPDATE %s SET %s=NULL WHERE %s IN (%s)" % \
(backend.quote_name(cls._meta.db_table), (backend.quote_name(cls._meta.db_table),
backend.quote_name(field.column), backend.quote_name(field.column),
@ -877,7 +866,7 @@ def delete_objects(seen_objs):
# NULL the primary key of the found objects, and perform post-notification. # NULL the primary key of the found objects, and perform post-notification.
for pk_val, instance in seen_objs[cls]: for pk_val, instance in seen_objs[cls]:
for field in cls._meta.fields: for field in cls._meta.fields:
if field.rel and field.null and field.rel.to in seen_classes: if field.rel and field.null and field.rel.to in seen_objs:
setattr(instance, field.attname, None) setattr(instance, field.attname, None)
setattr(instance, cls._meta.pk.attname, None) setattr(instance, cls._meta.pk.attname, None)

View File

@ -60,21 +60,23 @@ class SortedDict(dict):
yield k yield k
def items(self): def items(self):
for k in self.keyOrder: return zip(self.keyOrder, self.values())
yield k, dict.__getitem__(self, k)
def keys(self): def keys(self):
for k in self.keyOrder: return self.keyOrder[:]
yield k
def values(self): def values(self):
for k in self.keyOrder: return [dict.__getitem__(self,k) for k in self.keyOrder]
yield dict.__getitem__(self, k)
def update(self, dict): def update(self, dict):
for k, v in dict.items(): for k, v in dict.items():
self.__setitem__(k, v) self.__setitem__(k, v)
def setdefault(self, key, default):
if key not in self.keyOrder:
self.keyOrder.append(key)
return dict.setdefault(self, key, default)
class MultiValueDictKeyError(KeyError): class MultiValueDictKeyError(KeyError):
pass pass