test_field_flags.py 6.8 KB

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