Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Added tests for corner case with deleting where objects are deleted i…

…n the wrong order.

These tests currently fail, by design, fix will be committed shortly.


git-svn-id: http://code.djangoproject.com/svn/django/trunk@7721 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 7c621535a2b7a7cc58ed3658ab1f5a74d03abca3 1 parent 17bc282
@spookylukey spookylukey authored
View
12 django/db/models/loading.py
@@ -2,6 +2,8 @@
from django.conf import settings
from django.core.exceptions import ImproperlyConfigured
+from django.utils.datastructures import SortedDict
+
import sys
import os
import threading
@@ -18,10 +20,10 @@ class AppCache(object):
# http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/66531.
__shared_state = dict(
# Keys of app_store are the model modules for each application.
- app_store = {},
+ app_store = SortedDict(),
# Mapping of app_labels to a dictionary of model names to model code.
- app_models = {},
+ app_models = SortedDict(),
# Mapping of app_labels to errors raised when trying to import the app.
app_errors = {},
@@ -133,7 +135,7 @@ def get_models(self, app_mod=None):
"""
self._populate()
if app_mod:
- return self.app_models.get(app_mod.__name__.split('.')[-2], {}).values()
+ return self.app_models.get(app_mod.__name__.split('.')[-2], SortedDict()).values()
else:
model_list = []
for app_entry in self.app_models.itervalues():
@@ -149,7 +151,7 @@ def get_model(self, app_label, model_name, seed_cache=True):
"""
if seed_cache:
self._populate()
- return self.app_models.get(app_label, {}).get(model_name.lower())
+ return self.app_models.get(app_label, SortedDict()).get(model_name.lower())
def register_models(self, app_label, *models):
"""
@@ -159,7 +161,7 @@ def register_models(self, app_label, *models):
# Store as 'name: model' pair in a dictionary
# in the app_models dictionary
model_name = model._meta.object_name.lower()
- model_dict = self.app_models.setdefault(app_label, {})
+ model_dict = self.app_models.setdefault(app_label, SortedDict())
if model_name in model_dict:
# The same model may be imported via different paths (e.g.
# appname.models and project.appname.models). We use the source
View
1  tests/modeltests/delete/__init__.py
@@ -0,0 +1 @@
+
View
102 tests/modeltests/delete/models.py
@@ -0,0 +1,102 @@
+# coding: utf-8
+"""
+Tests for some corner cases with deleting.
+"""
+
+from django.db import models
+
+class DefaultRepr(object):
+ def __repr__(self):
+ return u"<%s: %s>" % (self.__class__.__name__, self.__dict__)
+
+class A(DefaultRepr, models.Model):
+ pass
+
+class B(DefaultRepr, models.Model):
+ a = models.ForeignKey(A)
+
+class C(DefaultRepr, models.Model):
+ b = models.ForeignKey(B)
+
+class D(DefaultRepr, models.Model):
+ c = models.ForeignKey(C)
+ a = models.ForeignKey(A)
+
+# Simplified, we have:
+# A
+# B -> A
+# C -> B
+# D -> C
+# D -> A
+
+# So, we must delete Ds first of all, then Cs then Bs then As.
+# However, if we start at As, we might find Bs first (in which
+# case things will be nice), or find Ds first.
+
+
+__test__ = {'API_TESTS': """
+# Due to the way that transactions work in the test harness,
+# doing m.delete() here can work but fail in a real situation,
+# since it may delete all objects, but not in the right order.
+# So we manually check that the order of deletion is correct.
+
+# Also, it is possible that the order is correct 'accidentally', due
+# solely to order of imports etc. To check this, we set the order
+# that 'get_models()' will retrieve to a known 'tricky' order, and
+# then try again with the reverse and try again. Slightly naughty
+# access to internals here.
+
+>>> from django.utils.datastructures import SortedDict
+>>> from django.db.models.loading import cache
+
+# Nice order
+>>> cache.app_models['delete'].keyOrder = ['a', 'b', 'c', 'd']
+>>> del A._meta._related_objects_cache
+>>> del B._meta._related_objects_cache
+>>> del C._meta._related_objects_cache
+>>> del D._meta._related_objects_cache
+
+
+
+>>> a1 = A()
+>>> a1.save()
+>>> b1 = B(a=a1)
+>>> b1.save()
+>>> c1 = C(b=b1)
+>>> c1.save()
+>>> d1 = D(c=c1, a=a1)
+>>> d1.save()
+
+>>> sd = SortedDict()
+>>> a1._collect_sub_objects(sd)
+>>> list(reversed(sd.keys()))
+[<class 'modeltests.delete.models.D'>, <class 'modeltests.delete.models.C'>, <class 'modeltests.delete.models.B'>, <class 'modeltests.delete.models.A'>]
+>>> a1.delete()
+
+# Same again with a known bad order
+>>> cache.app_models['delete'].keyOrder = ['d', 'c', 'b', 'a']
+>>> del A._meta._related_objects_cache
+>>> del B._meta._related_objects_cache
+>>> del C._meta._related_objects_cache
+>>> del D._meta._related_objects_cache
+
+
+>>> a2 = A()
+>>> a2.save()
+>>> b2 = B(a=a2)
+>>> b2.save()
+>>> c2 = C(b=b2)
+>>> c2.save()
+>>> d2 = D(c=c2, a=a2)
+>>> d2.save()
+
+>>> sd2 = SortedDict()
+>>> a2._collect_sub_objects(sd2)
+>>> list(reversed(sd2.keys()))
+[<class 'modeltests.delete.models.D'>, <class 'modeltests.delete.models.C'>, <class 'modeltests.delete.models.B'>, <class 'modeltests.delete.models.A'>]
+>>> a2.delete()
+
+
+
+"""
+}
Please sign in to comment.
Something went wrong with that request. Please try again.