test_field_flags.py 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. from django import test
  2. from django.contrib.contenttypes.fields import (
  3. GenericForeignKey, GenericRelation,
  4. )
  5. from django.db import models
  6. from .models import AllFieldsModel
  7. NON_CONCRETE_FIELDS = (
  8. models.ForeignObject,
  9. GenericForeignKey,
  10. GenericRelation,
  11. )
  12. NON_EDITABLE_FIELDS = (
  13. models.BinaryField,
  14. GenericForeignKey,
  15. GenericRelation,
  16. )
  17. RELATION_FIELDS = (
  18. models.ForeignKey,
  19. models.ForeignObject,
  20. models.ManyToManyField,
  21. models.OneToOneField,
  22. GenericForeignKey,
  23. GenericRelation,
  24. )
  25. MANY_TO_MANY_CLASSES = {
  26. models.ManyToManyField,
  27. }
  28. MANY_TO_ONE_CLASSES = {
  29. models.ForeignObject,
  30. models.ForeignKey,
  31. GenericForeignKey,
  32. }
  33. ONE_TO_MANY_CLASSES = {
  34. models.ForeignObjectRel,
  35. models.ManyToOneRel,
  36. GenericRelation,
  37. }
  38. ONE_TO_ONE_CLASSES = {
  39. models.OneToOneField,
  40. }
  41. FLAG_PROPERTIES = (
  42. 'concrete',
  43. 'editable',
  44. 'is_relation',
  45. 'model',
  46. 'hidden',
  47. 'one_to_many',
  48. 'many_to_one',
  49. 'many_to_many',
  50. 'one_to_one',
  51. 'related_model',
  52. )
  53. FLAG_PROPERTIES_FOR_RELATIONS = (
  54. 'one_to_many',
  55. 'many_to_one',
  56. 'many_to_many',
  57. 'one_to_one',
  58. )
  59. class FieldFlagsTests(test.SimpleTestCase):
  60. @classmethod
  61. def setUpClass(cls):
  62. super().setUpClass()
  63. cls.fields = [
  64. *AllFieldsModel._meta.fields,
  65. *AllFieldsModel._meta.private_fields,
  66. ]
  67. cls.all_fields = [
  68. *cls.fields,
  69. *AllFieldsModel._meta.many_to_many,
  70. *AllFieldsModel._meta.private_fields,
  71. ]
  72. cls.fields_and_reverse_objects = [
  73. *cls.all_fields,
  74. *AllFieldsModel._meta.related_objects,
  75. ]
  76. def test_each_field_should_have_a_concrete_attribute(self):
  77. self.assertTrue(all(f.concrete.__class__ == bool for f in self.fields))
  78. def test_each_field_should_have_an_editable_attribute(self):
  79. self.assertTrue(all(f.editable.__class__ == bool for f in self.all_fields))
  80. def test_each_field_should_have_a_has_rel_attribute(self):
  81. self.assertTrue(all(f.is_relation.__class__ == bool for f in self.all_fields))
  82. def test_each_object_should_have_auto_created(self):
  83. self.assertTrue(
  84. all(f.auto_created.__class__ == bool for f in self.fields_and_reverse_objects)
  85. )
  86. def test_non_concrete_fields(self):
  87. for field in self.fields:
  88. if type(field) in NON_CONCRETE_FIELDS:
  89. self.assertFalse(field.concrete)
  90. else:
  91. self.assertTrue(field.concrete)
  92. def test_non_editable_fields(self):
  93. for field in self.all_fields:
  94. if type(field) in NON_EDITABLE_FIELDS:
  95. self.assertFalse(field.editable)
  96. else:
  97. self.assertTrue(field.editable)
  98. def test_related_fields(self):
  99. for field in self.all_fields:
  100. if type(field) in RELATION_FIELDS:
  101. self.assertTrue(field.is_relation)
  102. else:
  103. self.assertFalse(field.is_relation)
  104. def test_field_names_should_always_be_available(self):
  105. for field in self.fields_and_reverse_objects:
  106. self.assertTrue(field.name)
  107. def test_all_field_types_should_have_flags(self):
  108. for field in self.fields_and_reverse_objects:
  109. for flag in FLAG_PROPERTIES:
  110. self.assertTrue(hasattr(field, flag), "Field %s does not have flag %s" % (field, flag))
  111. if field.is_relation:
  112. true_cardinality_flags = sum(
  113. getattr(field, flag) is True
  114. for flag in FLAG_PROPERTIES_FOR_RELATIONS
  115. )
  116. # If the field has a relation, there should be only one of the
  117. # 4 cardinality flags available.
  118. self.assertEqual(1, true_cardinality_flags)
  119. def test_cardinality_m2m(self):
  120. m2m_type_fields = [
  121. f for f in self.all_fields
  122. if f.is_relation and f.many_to_many
  123. ]
  124. # Test classes are what we expect
  125. self.assertEqual(MANY_TO_MANY_CLASSES, {f.__class__ for f in m2m_type_fields})
  126. # Ensure all m2m reverses are m2m
  127. for field in m2m_type_fields:
  128. reverse_field = field.remote_field
  129. self.assertTrue(reverse_field.is_relation)
  130. self.assertTrue(reverse_field.many_to_many)
  131. self.assertTrue(reverse_field.related_model)
  132. def test_cardinality_o2m(self):
  133. o2m_type_fields = [
  134. f for f in self.fields_and_reverse_objects
  135. if f.is_relation and f.one_to_many
  136. ]
  137. # Test classes are what we expect
  138. self.assertEqual(ONE_TO_MANY_CLASSES, {f.__class__ for f in o2m_type_fields})
  139. # Ensure all o2m reverses are m2o
  140. for field in o2m_type_fields:
  141. if field.concrete:
  142. reverse_field = field.remote_field
  143. self.assertTrue(reverse_field.is_relation and reverse_field.many_to_one)
  144. def test_cardinality_m2o(self):
  145. m2o_type_fields = [
  146. f for f in self.fields_and_reverse_objects
  147. if f.is_relation and f.many_to_one
  148. ]
  149. # Test classes are what we expect
  150. self.assertEqual(MANY_TO_ONE_CLASSES, {f.__class__ for f in m2o_type_fields})
  151. # Ensure all m2o reverses are o2m
  152. for obj in m2o_type_fields:
  153. if hasattr(obj, 'field'):
  154. reverse_field = obj.field
  155. self.assertTrue(reverse_field.is_relation and reverse_field.one_to_many)
  156. def test_cardinality_o2o(self):
  157. o2o_type_fields = [
  158. f for f in self.all_fields
  159. if f.is_relation and f.one_to_one
  160. ]
  161. # Test classes are what we expect
  162. self.assertEqual(ONE_TO_ONE_CLASSES, {f.__class__ for f in o2o_type_fields})
  163. # Ensure all o2o reverses are o2o
  164. for obj in o2o_type_fields:
  165. if hasattr(obj, 'field'):
  166. reverse_field = obj.field
  167. self.assertTrue(reverse_field.is_relation and reverse_field.one_to_one)
  168. def test_hidden_flag(self):
  169. incl_hidden = set(AllFieldsModel._meta.get_fields(include_hidden=True))
  170. no_hidden = set(AllFieldsModel._meta.get_fields())
  171. fields_that_should_be_hidden = (incl_hidden - no_hidden)
  172. for f in incl_hidden:
  173. self.assertEqual(f in fields_that_should_be_hidden, f.hidden)
  174. def test_model_and_reverse_model_should_equal_on_relations(self):
  175. for field in AllFieldsModel._meta.get_fields():
  176. is_concrete_forward_field = field.concrete and field.related_model
  177. if is_concrete_forward_field:
  178. reverse_field = field.remote_field
  179. self.assertEqual(field.model, reverse_field.related_model)
  180. self.assertEqual(field.related_model, reverse_field.model)
  181. def test_null(self):
  182. # null isn't well defined for a ManyToManyField, but changing it to
  183. # True causes backwards compatibility problems (#25320).
  184. self.assertFalse(AllFieldsModel._meta.get_field('m2m').null)
  185. self.assertTrue(AllFieldsModel._meta.get_field('reverse2').null)