PageRenderTime 119ms CodeModel.GetById 35ms app.highlight 50ms RepoModel.GetById 31ms app.codeStats 0ms

/tests/modeltests/delete/tests.py

https://code.google.com/p/mango-py/
Python | 253 lines | 193 code | 45 blank | 15 comment | 11 complexity | e56abe6f20a13f6433125ec71831c07e MD5 | raw file
  1from django.db import models, IntegrityError
  2from django.test import TestCase, skipUnlessDBFeature, skipIfDBFeature
  3
  4from modeltests.delete.models import (R, RChild, S, T, U, A, M, MR, MRNull,
  5    create_a, get_default_r, User, Avatar, HiddenUser, HiddenUserProfile)
  6
  7
  8class OnDeleteTests(TestCase):
  9    def setUp(self):
 10        self.DEFAULT = get_default_r()
 11
 12    def test_auto(self):
 13        a = create_a('auto')
 14        a.auto.delete()
 15        self.assertFalse(A.objects.filter(name='auto').exists())
 16
 17    def test_auto_nullable(self):
 18        a = create_a('auto_nullable')
 19        a.auto_nullable.delete()
 20        self.assertFalse(A.objects.filter(name='auto_nullable').exists())
 21
 22    def test_setvalue(self):
 23        a = create_a('setvalue')
 24        a.setvalue.delete()
 25        a = A.objects.get(pk=a.pk)
 26        self.assertEqual(self.DEFAULT, a.setvalue)
 27
 28    def test_setnull(self):
 29        a = create_a('setnull')
 30        a.setnull.delete()
 31        a = A.objects.get(pk=a.pk)
 32        self.assertEqual(None, a.setnull)
 33
 34    def test_setdefault(self):
 35        a = create_a('setdefault')
 36        a.setdefault.delete()
 37        a = A.objects.get(pk=a.pk)
 38        self.assertEqual(self.DEFAULT, a.setdefault)
 39
 40    def test_setdefault_none(self):
 41        a = create_a('setdefault_none')
 42        a.setdefault_none.delete()
 43        a = A.objects.get(pk=a.pk)
 44        self.assertEqual(None, a.setdefault_none)
 45
 46    def test_cascade(self):
 47        a = create_a('cascade')
 48        a.cascade.delete()
 49        self.assertFalse(A.objects.filter(name='cascade').exists())
 50
 51    def test_cascade_nullable(self):
 52        a = create_a('cascade_nullable')
 53        a.cascade_nullable.delete()
 54        self.assertFalse(A.objects.filter(name='cascade_nullable').exists())
 55
 56    def test_protect(self):
 57        a = create_a('protect')
 58        self.assertRaises(IntegrityError, a.protect.delete)
 59
 60    def test_do_nothing(self):
 61        # Testing DO_NOTHING is a bit harder: It would raise IntegrityError for a normal model,
 62        # so we connect to pre_delete and set the fk to a known value.
 63        replacement_r = R.objects.create()
 64        def check_do_nothing(sender, **kwargs):
 65            obj = kwargs['instance']
 66            obj.donothing_set.update(donothing=replacement_r)
 67        models.signals.pre_delete.connect(check_do_nothing)
 68        a = create_a('do_nothing')
 69        a.donothing.delete()
 70        a = A.objects.get(pk=a.pk)
 71        self.assertEqual(replacement_r, a.donothing)
 72        models.signals.pre_delete.disconnect(check_do_nothing)
 73
 74    def test_inheritance_cascade_up(self):
 75        child = RChild.objects.create()
 76        child.delete()
 77        self.assertFalse(R.objects.filter(pk=child.pk).exists())
 78
 79    def test_inheritance_cascade_down(self):
 80        child = RChild.objects.create()
 81        parent = child.r_ptr
 82        parent.delete()
 83        self.assertFalse(RChild.objects.filter(pk=child.pk).exists())
 84
 85    def test_cascade_from_child(self):
 86        a = create_a('child')
 87        a.child.delete()
 88        self.assertFalse(A.objects.filter(name='child').exists())
 89        self.assertFalse(R.objects.filter(pk=a.child_id).exists())
 90
 91    def test_cascade_from_parent(self):
 92        a = create_a('child')
 93        R.objects.get(pk=a.child_id).delete()
 94        self.assertFalse(A.objects.filter(name='child').exists())
 95        self.assertFalse(RChild.objects.filter(pk=a.child_id).exists())
 96
 97    def test_setnull_from_child(self):
 98        a = create_a('child_setnull')
 99        a.child_setnull.delete()
100        self.assertFalse(R.objects.filter(pk=a.child_setnull_id).exists())
101
102        a = A.objects.get(pk=a.pk)
103        self.assertEqual(None, a.child_setnull)
104
105    def test_setnull_from_parent(self):
106        a = create_a('child_setnull')
107        R.objects.get(pk=a.child_setnull_id).delete()
108        self.assertFalse(RChild.objects.filter(pk=a.child_setnull_id).exists())
109
110        a = A.objects.get(pk=a.pk)
111        self.assertEqual(None, a.child_setnull)
112
113    def test_o2o_setnull(self):
114        a = create_a('o2o_setnull')
115        a.o2o_setnull.delete()
116        a = A.objects.get(pk=a.pk)
117        self.assertEqual(None, a.o2o_setnull)
118
119
120class DeletionTests(TestCase):
121    def test_m2m(self):
122        m = M.objects.create()
123        r = R.objects.create()
124        MR.objects.create(m=m, r=r)
125        r.delete()
126        self.assertFalse(MR.objects.exists())
127
128        r = R.objects.create()
129        MR.objects.create(m=m, r=r)
130        m.delete()
131        self.assertFalse(MR.objects.exists())
132
133        m = M.objects.create()
134        r = R.objects.create()
135        m.m2m.add(r)
136        r.delete()
137        through = M._meta.get_field('m2m').rel.through
138        self.assertFalse(through.objects.exists())
139
140        r = R.objects.create()
141        m.m2m.add(r)
142        m.delete()
143        self.assertFalse(through.objects.exists())
144
145        m = M.objects.create()
146        r = R.objects.create()
147        MRNull.objects.create(m=m, r=r)
148        r.delete()
149        self.assertFalse(not MRNull.objects.exists())
150        self.assertFalse(m.m2m_through_null.exists())
151
152    def test_bulk(self):
153        from django.db.models.sql.constants import GET_ITERATOR_CHUNK_SIZE
154        s = S.objects.create(r=R.objects.create())
155        for i in xrange(2*GET_ITERATOR_CHUNK_SIZE):
156            T.objects.create(s=s)
157        #   1 (select related `T` instances)
158        # + 1 (select related `U` instances)
159        # + 2 (delete `T` instances in batches)
160        # + 1 (delete `s`)
161        self.assertNumQueries(5, s.delete)
162        self.assertFalse(S.objects.exists())
163
164    def test_instance_update(self):
165        deleted = []
166        related_setnull_sets = []
167        def pre_delete(sender, **kwargs):
168            obj = kwargs['instance']
169            deleted.append(obj)
170            if isinstance(obj, R):
171                related_setnull_sets.append(list(a.pk for a in obj.setnull_set.all()))
172
173        models.signals.pre_delete.connect(pre_delete)
174        a = create_a('update_setnull')
175        a.setnull.delete()
176
177        a = create_a('update_cascade')
178        a.cascade.delete()
179
180        for obj in deleted:
181            self.assertEqual(None, obj.pk)
182
183        for pk_list in related_setnull_sets:
184            for a in A.objects.filter(id__in=pk_list):
185                self.assertEqual(None, a.setnull)
186
187        models.signals.pre_delete.disconnect(pre_delete)
188
189    def test_deletion_order(self):
190        pre_delete_order = []
191        post_delete_order = []
192
193        def log_post_delete(sender, **kwargs):
194            pre_delete_order.append((sender, kwargs['instance'].pk))
195
196        def log_pre_delete(sender, **kwargs):
197            post_delete_order.append((sender, kwargs['instance'].pk))
198
199        models.signals.post_delete.connect(log_post_delete)
200        models.signals.pre_delete.connect(log_pre_delete)
201
202        r = R.objects.create(pk=1)
203        s1 = S.objects.create(pk=1, r=r)
204        s2 = S.objects.create(pk=2, r=r)
205        t1 = T.objects.create(pk=1, s=s1)
206        t2 = T.objects.create(pk=2, s=s2)
207        r.delete()
208        self.assertEqual(
209            pre_delete_order, [(T, 2), (T, 1), (S, 2), (S, 1), (R, 1)]
210        )
211        self.assertEqual(
212            post_delete_order, [(T, 1), (T, 2), (S, 1), (S, 2), (R, 1)]
213        )
214
215        models.signals.post_delete.disconnect(log_post_delete)
216        models.signals.post_delete.disconnect(log_pre_delete)
217
218    @skipUnlessDBFeature("can_defer_constraint_checks")
219    def test_can_defer_constraint_checks(self):
220        u = User.objects.create(
221            avatar=Avatar.objects.create()
222        )
223        a = Avatar.objects.get(pk=u.avatar_id)
224        # 1 query to find the users for the avatar.
225        # 1 query to delete the user
226        # 1 query to delete the avatar
227        # The important thing is that when we can defer constraint checks there
228        # is no need to do an UPDATE on User.avatar to null it out.
229        self.assertNumQueries(3, a.delete)
230        self.assertFalse(User.objects.exists())
231        self.assertFalse(Avatar.objects.exists())
232
233    @skipIfDBFeature("can_defer_constraint_checks")
234    def test_cannot_defer_constraint_checks(self):
235        u = User.objects.create(
236            avatar=Avatar.objects.create()
237        )
238        a = Avatar.objects.get(pk=u.avatar_id)
239        # 1 query to find the users for the avatar.
240        # 1 query to delete the user
241        # 1 query to null out user.avatar, because we can't defer the constraint
242        # 1 query to delete the avatar
243        self.assertNumQueries(4, a.delete)
244        self.assertFalse(User.objects.exists())
245        self.assertFalse(Avatar.objects.exists())
246
247    def test_hidden_related(self):
248        r = R.objects.create()
249        h = HiddenUser.objects.create(r=r)
250        p = HiddenUserProfile.objects.create(user=h)
251
252        r.delete()
253        self.assertEqual(HiddenUserProfile.objects.count(), 0)