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