File: tests.py

package info (click to toggle)
python-django 3%3A5.2.5-1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 61,236 kB
  • sloc: python: 361,585; javascript: 19,250; xml: 211; makefile: 182; sh: 28
file content (183 lines) | stat: -rw-r--r-- 7,634 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
from django.db import DatabaseError, IntegrityError, models, transaction
from django.test import TestCase

from .models import (
    Counter,
    DiamondSubSubCounter,
    InheritedCounter,
    OtherSubCounter,
    ProxyCounter,
    SubCounter,
    SubSubCounter,
    WithCustomPK,
)


class ForceTests(TestCase):
    def test_force_update(self):
        c = Counter.objects.create(name="one", value=1)

        # The normal case
        c.value = 2
        c.save()
        # Same thing, via an update
        c.value = 3
        c.save(force_update=True)

        # Won't work because force_update and force_insert are mutually
        # exclusive
        c.value = 4
        msg = "Cannot force both insert and updating in model saving."
        with self.assertRaisesMessage(ValueError, msg):
            c.save(force_insert=True, force_update=True)

        # Try to update something that doesn't have a primary key in the first
        # place.
        c1 = Counter(name="two", value=2)
        msg = "Cannot force an update in save() with no primary key."
        with self.assertRaisesMessage(ValueError, msg):
            with transaction.atomic():
                c1.save(force_update=True)
        c1.save(force_insert=True)

        # Won't work because we can't insert a pk of the same value.
        c.value = 5
        with self.assertRaises(IntegrityError):
            with transaction.atomic():
                c.save(force_insert=True)

        # Trying to update should still fail, even with manual primary keys, if
        # the data isn't in the database already.
        obj = WithCustomPK(name=1, value=1)
        msg = "Forced update did not affect any rows."
        with self.assertRaisesMessage(DatabaseError, msg):
            with transaction.atomic():
                obj.save(force_update=True)


class InheritanceTests(TestCase):
    def test_force_update_on_inherited_model(self):
        a = InheritedCounter(name="count", value=1, tag="spam")
        a.save()
        a.save(force_update=True)

    def test_force_update_on_proxy_model(self):
        a = ProxyCounter(name="count", value=1)
        a.save()
        a.save(force_update=True)

    def test_force_update_on_inherited_model_without_fields(self):
        """
        Issue 13864: force_update fails on subclassed models, if they don't
        specify custom fields.
        """
        a = SubCounter(name="count", value=1)
        a.save()
        a.value = 2
        a.save(force_update=True)


class ForceInsertInheritanceTests(TestCase):
    def test_force_insert_not_bool_or_tuple(self):
        msg = "force_insert must be a bool or tuple."
        with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
            Counter().save(force_insert=1)
        with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
            Counter().save(force_insert="test")
        with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
            Counter().save(force_insert=[])

    def test_force_insert_not_model(self):
        msg = f"Invalid force_insert member. {object!r} must be a model subclass."
        with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
            Counter().save(force_insert=(object,))
        instance = Counter()
        msg = f"Invalid force_insert member. {instance!r} must be a model subclass."
        with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
            Counter().save(force_insert=(instance,))

    def test_force_insert_not_base(self):
        msg = "Invalid force_insert member. SubCounter must be a base of Counter."
        with self.assertRaisesMessage(TypeError, msg):
            Counter().save(force_insert=(SubCounter,))

    def test_force_insert_false(self):
        with self.assertNumQueries(3):
            obj = SubCounter.objects.create(pk=1, value=0)
        with self.assertNumQueries(2):
            SubCounter(pk=obj.pk, value=1).save()
        obj.refresh_from_db()
        self.assertEqual(obj.value, 1)
        with self.assertNumQueries(2):
            SubCounter(pk=obj.pk, value=2).save(force_insert=False)
        obj.refresh_from_db()
        self.assertEqual(obj.value, 2)
        with self.assertNumQueries(2):
            SubCounter(pk=obj.pk, value=3).save(force_insert=())
        obj.refresh_from_db()
        self.assertEqual(obj.value, 3)

    def test_force_insert_false_with_existing_parent(self):
        parent = Counter.objects.create(pk=1, value=1)
        with self.assertNumQueries(2):
            SubCounter.objects.create(pk=parent.pk, value=2)

    def test_force_insert_parent(self):
        with self.assertNumQueries(3):
            SubCounter(pk=1, value=1).save(force_insert=True)
        # Force insert a new parent and don't UPDATE first.
        with self.assertNumQueries(2):
            SubCounter(pk=2, value=1).save(force_insert=(Counter,))
        with self.assertNumQueries(2):
            SubCounter(pk=3, value=1).save(force_insert=(models.Model,))

    def test_force_insert_with_grandparent(self):
        with self.assertNumQueries(4):
            SubSubCounter(pk=1, value=1).save(force_insert=True)
        # Force insert parents on all levels and don't UPDATE first.
        with self.assertNumQueries(3):
            SubSubCounter(pk=2, value=1).save(force_insert=(models.Model,))
        with self.assertNumQueries(3):
            SubSubCounter(pk=3, value=1).save(force_insert=(Counter,))
        # Force insert only the last parent.
        with self.assertNumQueries(4):
            SubSubCounter(pk=4, value=1).save(force_insert=(SubCounter,))

    def test_force_insert_with_existing_grandparent(self):
        # Force insert only the last child.
        grandparent = Counter.objects.create(pk=1, value=1)
        with self.assertNumQueries(4):
            SubSubCounter(pk=grandparent.pk, value=1).save(force_insert=True)
        # Force insert a parent, and don't force insert a grandparent.
        grandparent = Counter.objects.create(pk=2, value=1)
        with self.assertNumQueries(3):
            SubSubCounter(pk=grandparent.pk, value=1).save(force_insert=(SubCounter,))
        # Force insert parents on all levels, grandparent conflicts.
        grandparent = Counter.objects.create(pk=3, value=1)
        with self.assertRaises(IntegrityError), transaction.atomic():
            SubSubCounter(pk=grandparent.pk, value=1).save(force_insert=(Counter,))

    def test_force_insert_diamond_mti(self):
        # Force insert all parents.
        with self.assertNumQueries(4):
            DiamondSubSubCounter(pk=1, value=1).save(
                force_insert=(Counter, SubCounter, OtherSubCounter)
            )
        with self.assertNumQueries(4):
            DiamondSubSubCounter(pk=2, value=1).save(force_insert=(models.Model,))
        # Force insert parents, and don't force insert a common grandparent.
        with self.assertNumQueries(5):
            DiamondSubSubCounter(pk=3, value=1).save(
                force_insert=(SubCounter, OtherSubCounter)
            )
        grandparent = Counter.objects.create(pk=4, value=1)
        with self.assertNumQueries(4):
            DiamondSubSubCounter(pk=grandparent.pk, value=1).save(
                force_insert=(SubCounter, OtherSubCounter),
            )
        # Force insert all parents, grandparent conflicts.
        grandparent = Counter.objects.create(pk=5, value=1)
        with self.assertRaises(IntegrityError), transaction.atomic():
            DiamondSubSubCounter(pk=grandparent.pk, value=1).save(
                force_insert=(models.Model,)
            )