mirror of
https://github.com/django/django.git
synced 2025-10-31 09:41:08 +00:00
Fixed bug with Model.delete() which did not always delete objects in the right order.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@7722 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
@@ -33,8 +33,46 @@ class D(DefaultRepr, models.Model):
|
||||
# However, if we start at As, we might find Bs first (in which
|
||||
# case things will be nice), or find Ds first.
|
||||
|
||||
# Some mutually dependent models, but nullable
|
||||
class E(DefaultRepr, models.Model):
|
||||
f = models.ForeignKey('F', null=True, related_name='e_rel')
|
||||
|
||||
class F(DefaultRepr, models.Model):
|
||||
e = models.ForeignKey(E, related_name='f_rel')
|
||||
|
||||
|
||||
__test__ = {'API_TESTS': """
|
||||
# First, some tests for the datastructure we use
|
||||
|
||||
>>> from django.db.models.query import CollectedObjects
|
||||
|
||||
>>> g = CollectedObjects()
|
||||
>>> g.add("key1", 1, "item1", None)
|
||||
False
|
||||
>>> g["key1"]
|
||||
{1: 'item1'}
|
||||
>>> g.add("key2", 1, "item1", "key1")
|
||||
False
|
||||
>>> g.add("key2", 2, "item2", "key1")
|
||||
False
|
||||
>>> g["key2"]
|
||||
{1: 'item1', 2: 'item2'}
|
||||
>>> g.add("key3", 1, "item1", "key1")
|
||||
False
|
||||
>>> g.add("key3", 1, "item1", "key2")
|
||||
True
|
||||
>>> g.ordered_keys()
|
||||
['key3', 'key2', 'key1']
|
||||
|
||||
>>> g.add("key2", 1, "item1", "key3")
|
||||
True
|
||||
>>> g.ordered_keys()
|
||||
Traceback (most recent call last):
|
||||
...
|
||||
CyclicDependency: There is a cyclic dependency of items to be processed.
|
||||
|
||||
|
||||
|
||||
# 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.
|
||||
@@ -42,11 +80,10 @@ __test__ = {'API_TESTS': """
|
||||
|
||||
# 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.
|
||||
# that 'get_models()' will retrieve to a known 'nice' order, and
|
||||
# then try again with a known 'tricky' order. Slightly naughty
|
||||
# access to internals here :-)
|
||||
|
||||
>>> from django.utils.datastructures import SortedDict
|
||||
>>> from django.db.models.loading import cache
|
||||
|
||||
# Nice order
|
||||
@@ -56,8 +93,6 @@ __test__ = {'API_TESTS': """
|
||||
>>> del C._meta._related_objects_cache
|
||||
>>> del D._meta._related_objects_cache
|
||||
|
||||
|
||||
|
||||
>>> a1 = A()
|
||||
>>> a1.save()
|
||||
>>> b1 = B(a=a1)
|
||||
@@ -67,9 +102,9 @@ __test__ = {'API_TESTS': """
|
||||
>>> d1 = D(c=c1, a=a1)
|
||||
>>> d1.save()
|
||||
|
||||
>>> sd = SortedDict()
|
||||
>>> a1._collect_sub_objects(sd)
|
||||
>>> list(reversed(sd.keys()))
|
||||
>>> o = CollectedObjects()
|
||||
>>> a1._collect_sub_objects(o)
|
||||
>>> o.keys()
|
||||
[<class 'modeltests.delete.models.D'>, <class 'modeltests.delete.models.C'>, <class 'modeltests.delete.models.B'>, <class 'modeltests.delete.models.A'>]
|
||||
>>> a1.delete()
|
||||
|
||||
@@ -80,7 +115,6 @@ __test__ = {'API_TESTS': """
|
||||
>>> del C._meta._related_objects_cache
|
||||
>>> del D._meta._related_objects_cache
|
||||
|
||||
|
||||
>>> a2 = A()
|
||||
>>> a2.save()
|
||||
>>> b2 = B(a=a2)
|
||||
@@ -90,13 +124,56 @@ __test__ = {'API_TESTS': """
|
||||
>>> d2 = D(c=c2, a=a2)
|
||||
>>> d2.save()
|
||||
|
||||
>>> sd2 = SortedDict()
|
||||
>>> a2._collect_sub_objects(sd2)
|
||||
>>> list(reversed(sd2.keys()))
|
||||
>>> o = CollectedObjects()
|
||||
>>> a2._collect_sub_objects(o)
|
||||
>>> o.keys()
|
||||
[<class 'modeltests.delete.models.D'>, <class 'modeltests.delete.models.C'>, <class 'modeltests.delete.models.B'>, <class 'modeltests.delete.models.A'>]
|
||||
>>> a2.delete()
|
||||
|
||||
# Tests for nullable related fields
|
||||
|
||||
>>> g = CollectedObjects()
|
||||
>>> g.add("key1", 1, "item1", None)
|
||||
False
|
||||
>>> g.add("key2", 1, "item1", "key1", nullable=True)
|
||||
False
|
||||
>>> g.add("key1", 1, "item1", "key2")
|
||||
True
|
||||
>>> g.ordered_keys()
|
||||
['key1', 'key2']
|
||||
|
||||
>>> e1 = E()
|
||||
>>> e1.save()
|
||||
>>> f1 = F(e=e1)
|
||||
>>> f1.save()
|
||||
>>> e1.f = f1
|
||||
>>> e1.save()
|
||||
|
||||
# Since E.f is nullable, we should delete F first (after nulling out
|
||||
# the E.f field), then E.
|
||||
|
||||
>>> o = CollectedObjects()
|
||||
>>> e1._collect_sub_objects(o)
|
||||
>>> o.keys()
|
||||
[<class 'modeltests.delete.models.F'>, <class 'modeltests.delete.models.E'>]
|
||||
|
||||
>>> e1.delete()
|
||||
|
||||
>>> e2 = E()
|
||||
>>> e2.save()
|
||||
>>> f2 = F(e=e2)
|
||||
>>> f2.save()
|
||||
>>> e2.f = f2
|
||||
>>> e2.save()
|
||||
|
||||
# Same deal as before, though we are starting from the other object.
|
||||
|
||||
>>> o = CollectedObjects()
|
||||
>>> f2._collect_sub_objects(o)
|
||||
>>> o.keys()
|
||||
[<class 'modeltests.delete.models.F'>, <class 'modeltests.delete.models.E'>]
|
||||
|
||||
>>> f2.delete()
|
||||
|
||||
"""
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user