Commit 7c621535 authored by Luke Plant's avatar Luke Plant
Browse files

Added tests for corner case with deleting where objects are deleted in 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
parent 17bc2820
Loading
Loading
Loading
Loading
+7 −5
Original line number Diff line number Diff line
@@ -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 @@ class AppCache(object):
        """
        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 @@ class AppCache(object):
        """
        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 @@ class AppCache(object):
            # 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
+1 −0
Original line number Diff line number Diff line
+102 −0
Original line number Diff line number Diff line
# 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()



"""
}