diff --git a/django/db/models/base.py b/django/db/models/base.py index 7b299c19ac..fd29a3eaf4 100644 --- a/django/db/models/base.py +++ b/django/db/models/base.py @@ -10,6 +10,7 @@ from django.db.models import signals from django.db.models.loading import register_models from django.dispatch import dispatcher from django.core.exceptions import ObjectDoesNotExist +from django.utils.datastructures import SortedDict from django.utils.functional import curry from django.conf import settings 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) # Find all the objects than need to be deleted - seen_objs = {} + seen_objs = SortedDict() self._collect_sub_objects(seen_objs) # Actually delete the objects diff --git a/django/db/models/query.py b/django/db/models/query.py index a3b798debe..ae45e9580a 100644 --- a/django/db/models/query.py +++ b/django/db/models/query.py @@ -234,7 +234,7 @@ class QuerySet(object): # Collect all the objects to be deleted, and all the objects that are related to # the objects that are to be deleted - seen_objs = {} + seen_objs = SortedDict() for object in del_query: object._collect_sub_objects(seen_objs) @@ -815,22 +815,11 @@ def lookup_inner(path, clause, value, opts, table, column): 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): "Iterate through a list of seen classes, and remove any instances that are referred to" - seen_classes = set(seen_objs.keys()) - ordered_classes = list(seen_classes) - ordered_classes.sort(compare_models) - + ordered_classes = seen_objs.keys() + ordered_classes.reverse() + cursor = connection.cursor() for cls in ordered_classes: @@ -855,7 +844,7 @@ def delete_objects(seen_objs): ','.join(['%s' for pk in pk_list])), pk_list) 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)" % \ (backend.quote_name(cls._meta.db_table), 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. for pk_val, instance in seen_objs[cls]: 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, cls._meta.pk.attname, None) diff --git a/django/utils/datastructures.py b/django/utils/datastructures.py index 4ad7bc52da..ed7a848636 100644 --- a/django/utils/datastructures.py +++ b/django/utils/datastructures.py @@ -60,21 +60,23 @@ class SortedDict(dict): yield k def items(self): - for k in self.keyOrder: - yield k, dict.__getitem__(self, k) + return zip(self.keyOrder, self.values()) def keys(self): - for k in self.keyOrder: - yield k + return self.keyOrder[:] def values(self): - for k in self.keyOrder: - yield dict.__getitem__(self, k) + return [dict.__getitem__(self,k) for k in self.keyOrder] def update(self, dict): for k, v in dict.items(): 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): pass