2
0

tests.py 7.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183
  1. from django.db import DatabaseError, IntegrityError, models, transaction
  2. from django.test import TestCase
  3. from .models import (
  4. Counter,
  5. DiamondSubSubCounter,
  6. InheritedCounter,
  7. OtherSubCounter,
  8. ProxyCounter,
  9. SubCounter,
  10. SubSubCounter,
  11. WithCustomPK,
  12. )
  13. class ForceTests(TestCase):
  14. def test_force_update(self):
  15. c = Counter.objects.create(name="one", value=1)
  16. # The normal case
  17. c.value = 2
  18. c.save()
  19. # Same thing, via an update
  20. c.value = 3
  21. c.save(force_update=True)
  22. # Won't work because force_update and force_insert are mutually
  23. # exclusive
  24. c.value = 4
  25. msg = "Cannot force both insert and updating in model saving."
  26. with self.assertRaisesMessage(ValueError, msg):
  27. c.save(force_insert=True, force_update=True)
  28. # Try to update something that doesn't have a primary key in the first
  29. # place.
  30. c1 = Counter(name="two", value=2)
  31. msg = "Cannot force an update in save() with no primary key."
  32. with self.assertRaisesMessage(ValueError, msg):
  33. with transaction.atomic():
  34. c1.save(force_update=True)
  35. c1.save(force_insert=True)
  36. # Won't work because we can't insert a pk of the same value.
  37. c.value = 5
  38. with self.assertRaises(IntegrityError):
  39. with transaction.atomic():
  40. c.save(force_insert=True)
  41. # Trying to update should still fail, even with manual primary keys, if
  42. # the data isn't in the database already.
  43. obj = WithCustomPK(name=1, value=1)
  44. msg = "Forced update did not affect any rows."
  45. with self.assertRaisesMessage(DatabaseError, msg):
  46. with transaction.atomic():
  47. obj.save(force_update=True)
  48. class InheritanceTests(TestCase):
  49. def test_force_update_on_inherited_model(self):
  50. a = InheritedCounter(name="count", value=1, tag="spam")
  51. a.save()
  52. a.save(force_update=True)
  53. def test_force_update_on_proxy_model(self):
  54. a = ProxyCounter(name="count", value=1)
  55. a.save()
  56. a.save(force_update=True)
  57. def test_force_update_on_inherited_model_without_fields(self):
  58. """
  59. Issue 13864: force_update fails on subclassed models, if they don't
  60. specify custom fields.
  61. """
  62. a = SubCounter(name="count", value=1)
  63. a.save()
  64. a.value = 2
  65. a.save(force_update=True)
  66. class ForceInsertInheritanceTests(TestCase):
  67. def test_force_insert_not_bool_or_tuple(self):
  68. msg = "force_insert must be a bool or tuple."
  69. with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
  70. Counter().save(force_insert=1)
  71. with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
  72. Counter().save(force_insert="test")
  73. with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
  74. Counter().save(force_insert=[])
  75. def test_force_insert_not_model(self):
  76. msg = f"Invalid force_insert member. {object!r} must be a model subclass."
  77. with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
  78. Counter().save(force_insert=(object,))
  79. instance = Counter()
  80. msg = f"Invalid force_insert member. {instance!r} must be a model subclass."
  81. with self.assertRaisesMessage(TypeError, msg), transaction.atomic():
  82. Counter().save(force_insert=(instance,))
  83. def test_force_insert_not_base(self):
  84. msg = "Invalid force_insert member. SubCounter must be a base of Counter."
  85. with self.assertRaisesMessage(TypeError, msg):
  86. Counter().save(force_insert=(SubCounter,))
  87. def test_force_insert_false(self):
  88. with self.assertNumQueries(3):
  89. obj = SubCounter.objects.create(pk=1, value=0)
  90. with self.assertNumQueries(2):
  91. SubCounter(pk=obj.pk, value=1).save()
  92. obj.refresh_from_db()
  93. self.assertEqual(obj.value, 1)
  94. with self.assertNumQueries(2):
  95. SubCounter(pk=obj.pk, value=2).save(force_insert=False)
  96. obj.refresh_from_db()
  97. self.assertEqual(obj.value, 2)
  98. with self.assertNumQueries(2):
  99. SubCounter(pk=obj.pk, value=3).save(force_insert=())
  100. obj.refresh_from_db()
  101. self.assertEqual(obj.value, 3)
  102. def test_force_insert_false_with_existing_parent(self):
  103. parent = Counter.objects.create(pk=1, value=1)
  104. with self.assertNumQueries(2):
  105. SubCounter.objects.create(pk=parent.pk, value=2)
  106. def test_force_insert_parent(self):
  107. with self.assertNumQueries(3):
  108. SubCounter(pk=1, value=1).save(force_insert=True)
  109. # Force insert a new parent and don't UPDATE first.
  110. with self.assertNumQueries(2):
  111. SubCounter(pk=2, value=1).save(force_insert=(Counter,))
  112. with self.assertNumQueries(2):
  113. SubCounter(pk=3, value=1).save(force_insert=(models.Model,))
  114. def test_force_insert_with_grandparent(self):
  115. with self.assertNumQueries(4):
  116. SubSubCounter(pk=1, value=1).save(force_insert=True)
  117. # Force insert parents on all levels and don't UPDATE first.
  118. with self.assertNumQueries(3):
  119. SubSubCounter(pk=2, value=1).save(force_insert=(models.Model,))
  120. with self.assertNumQueries(3):
  121. SubSubCounter(pk=3, value=1).save(force_insert=(Counter,))
  122. # Force insert only the last parent.
  123. with self.assertNumQueries(4):
  124. SubSubCounter(pk=4, value=1).save(force_insert=(SubCounter,))
  125. def test_force_insert_with_existing_grandparent(self):
  126. # Force insert only the last child.
  127. grandparent = Counter.objects.create(pk=1, value=1)
  128. with self.assertNumQueries(4):
  129. SubSubCounter(pk=grandparent.pk, value=1).save(force_insert=True)
  130. # Force insert a parent, and don't force insert a grandparent.
  131. grandparent = Counter.objects.create(pk=2, value=1)
  132. with self.assertNumQueries(3):
  133. SubSubCounter(pk=grandparent.pk, value=1).save(force_insert=(SubCounter,))
  134. # Force insert parents on all levels, grandparent conflicts.
  135. grandparent = Counter.objects.create(pk=3, value=1)
  136. with self.assertRaises(IntegrityError), transaction.atomic():
  137. SubSubCounter(pk=grandparent.pk, value=1).save(force_insert=(Counter,))
  138. def test_force_insert_diamond_mti(self):
  139. # Force insert all parents.
  140. with self.assertNumQueries(4):
  141. DiamondSubSubCounter(pk=1, value=1).save(
  142. force_insert=(Counter, SubCounter, OtherSubCounter)
  143. )
  144. with self.assertNumQueries(4):
  145. DiamondSubSubCounter(pk=2, value=1).save(force_insert=(models.Model,))
  146. # Force insert parents, and don't force insert a common grandparent.
  147. with self.assertNumQueries(5):
  148. DiamondSubSubCounter(pk=3, value=1).save(
  149. force_insert=(SubCounter, OtherSubCounter)
  150. )
  151. grandparent = Counter.objects.create(pk=4, value=1)
  152. with self.assertNumQueries(4):
  153. DiamondSubSubCounter(pk=grandparent.pk, value=1).save(
  154. force_insert=(SubCounter, OtherSubCounter),
  155. )
  156. # Force insert all parents, grandparent conflicts.
  157. grandparent = Counter.objects.create(pk=5, value=1)
  158. with self.assertRaises(IntegrityError), transaction.atomic():
  159. DiamondSubSubCounter(pk=grandparent.pk, value=1).save(
  160. force_insert=(models.Model,)
  161. )