tests.py 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. from django.db import IntegrityError, transaction
  2. from django.test import TestCase, skipIfDBFeature
  3. from .models import Bar, Business, Employee, Foo
  4. class BasicCustomPKTests(TestCase):
  5. @classmethod
  6. def setUpTestData(cls):
  7. cls.dan = Employee.objects.create(
  8. employee_code=123, first_name="Dan", last_name="Jones",
  9. )
  10. cls.fran = Employee.objects.create(
  11. employee_code=456, first_name="Fran", last_name="Bones",
  12. )
  13. cls.business = Business.objects.create(name="Sears")
  14. cls.business.employees.add(cls.dan, cls.fran)
  15. def test_querysets(self):
  16. """
  17. Both pk and custom attribute_name can be used in filter and friends
  18. """
  19. self.assertQuerysetEqual(
  20. Employee.objects.filter(pk=123), [
  21. "Dan Jones",
  22. ],
  23. str
  24. )
  25. self.assertQuerysetEqual(
  26. Employee.objects.filter(employee_code=123), [
  27. "Dan Jones",
  28. ],
  29. str
  30. )
  31. self.assertQuerysetEqual(
  32. Employee.objects.filter(pk__in=[123, 456]), [
  33. "Fran Bones",
  34. "Dan Jones",
  35. ],
  36. str
  37. )
  38. self.assertQuerysetEqual(
  39. Employee.objects.all(), [
  40. "Fran Bones",
  41. "Dan Jones",
  42. ],
  43. str
  44. )
  45. self.assertQuerysetEqual(
  46. Business.objects.filter(name="Sears"), [
  47. "Sears"
  48. ],
  49. lambda b: b.name
  50. )
  51. self.assertQuerysetEqual(
  52. Business.objects.filter(pk="Sears"), [
  53. "Sears",
  54. ],
  55. lambda b: b.name
  56. )
  57. def test_querysets_related_name(self):
  58. """
  59. Custom pk doesn't affect related_name based lookups
  60. """
  61. self.assertQuerysetEqual(
  62. self.business.employees.all(), [
  63. "Fran Bones",
  64. "Dan Jones",
  65. ],
  66. str
  67. )
  68. self.assertQuerysetEqual(
  69. self.fran.business_set.all(), [
  70. "Sears",
  71. ],
  72. lambda b: b.name
  73. )
  74. def test_querysets_relational(self):
  75. """
  76. Queries across tables, involving primary key
  77. """
  78. self.assertQuerysetEqual(
  79. Employee.objects.filter(business__name="Sears"), [
  80. "Fran Bones",
  81. "Dan Jones",
  82. ],
  83. str,
  84. )
  85. self.assertQuerysetEqual(
  86. Employee.objects.filter(business__pk="Sears"), [
  87. "Fran Bones",
  88. "Dan Jones",
  89. ],
  90. str,
  91. )
  92. self.assertQuerysetEqual(
  93. Business.objects.filter(employees__employee_code=123), [
  94. "Sears",
  95. ],
  96. lambda b: b.name
  97. )
  98. self.assertQuerysetEqual(
  99. Business.objects.filter(employees__pk=123), [
  100. "Sears",
  101. ],
  102. lambda b: b.name,
  103. )
  104. self.assertQuerysetEqual(
  105. Business.objects.filter(employees__first_name__startswith="Fran"), [
  106. "Sears",
  107. ],
  108. lambda b: b.name
  109. )
  110. def test_get(self):
  111. """
  112. Get can accept pk or the real attribute name
  113. """
  114. self.assertEqual(Employee.objects.get(pk=123), self.dan)
  115. self.assertEqual(Employee.objects.get(pk=456), self.fran)
  116. with self.assertRaises(Employee.DoesNotExist):
  117. Employee.objects.get(pk=42)
  118. # Use the name of the primary key, rather than pk.
  119. self.assertEqual(Employee.objects.get(employee_code=123), self.dan)
  120. def test_pk_attributes(self):
  121. """
  122. pk and attribute name are available on the model
  123. No default id attribute is added
  124. """
  125. # pk can be used as a substitute for the primary key.
  126. # The primary key can be accessed via the pk property on the model.
  127. e = Employee.objects.get(pk=123)
  128. self.assertEqual(e.pk, 123)
  129. # Or we can use the real attribute name for the primary key:
  130. self.assertEqual(e.employee_code, 123)
  131. with self.assertRaisesMessage(AttributeError, "'Employee' object has no attribute 'id'"):
  132. e.id
  133. def test_in_bulk(self):
  134. """
  135. Custom pks work with in_bulk, both for integer and non-integer types
  136. """
  137. emps = Employee.objects.in_bulk([123, 456])
  138. self.assertEqual(emps[123], self.dan)
  139. self.assertEqual(Business.objects.in_bulk(["Sears"]), {
  140. "Sears": self.business,
  141. })
  142. def test_save(self):
  143. """
  144. custom pks do not affect save
  145. """
  146. fran = Employee.objects.get(pk=456)
  147. fran.last_name = "Jones"
  148. fran.save()
  149. self.assertQuerysetEqual(
  150. Employee.objects.filter(last_name="Jones"), [
  151. "Dan Jones",
  152. "Fran Jones",
  153. ],
  154. str
  155. )
  156. class CustomPKTests(TestCase):
  157. def test_custom_pk_create(self):
  158. """
  159. New objects can be created both with pk and the custom name
  160. """
  161. Employee.objects.create(employee_code=1234, first_name="Foo", last_name="Bar")
  162. Employee.objects.create(pk=1235, first_name="Foo", last_name="Baz")
  163. Business.objects.create(name="Bears")
  164. Business.objects.create(pk="Tears")
  165. def test_unicode_pk(self):
  166. # Primary key may be Unicode string.
  167. Business.objects.create(name='jaźń')
  168. def test_unique_pk(self):
  169. # The primary key must also be unique, so trying to create a new object
  170. # with the same primary key will fail.
  171. Employee.objects.create(
  172. employee_code=123, first_name="Frank", last_name="Jones"
  173. )
  174. with self.assertRaises(IntegrityError):
  175. with transaction.atomic():
  176. Employee.objects.create(employee_code=123, first_name="Fred", last_name="Jones")
  177. def test_zero_non_autoincrement_pk(self):
  178. Employee.objects.create(
  179. employee_code=0, first_name="Frank", last_name="Jones"
  180. )
  181. employee = Employee.objects.get(pk=0)
  182. self.assertEqual(employee.employee_code, 0)
  183. def test_custom_field_pk(self):
  184. # Regression for #10785 -- Custom fields can be used for primary keys.
  185. new_bar = Bar.objects.create()
  186. new_foo = Foo.objects.create(bar=new_bar)
  187. f = Foo.objects.get(bar=new_bar.pk)
  188. self.assertEqual(f, new_foo)
  189. self.assertEqual(f.bar, new_bar)
  190. f = Foo.objects.get(bar=new_bar)
  191. self.assertEqual(f, new_foo),
  192. self.assertEqual(f.bar, new_bar)
  193. # SQLite lets objects be saved with an empty primary key, even though an
  194. # integer is expected. So we can't check for an error being raised in that
  195. # case for SQLite. Remove it from the suite for this next bit.
  196. @skipIfDBFeature('supports_unspecified_pk')
  197. def test_required_pk(self):
  198. # The primary key must be specified, so an error is raised if you
  199. # try to create an object without it.
  200. with self.assertRaises(IntegrityError):
  201. with transaction.atomic():
  202. Employee.objects.create(first_name="Tom", last_name="Smith")