1. from django.apps import apps
    
  2. from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
    
  3. from django.core.exceptions import FieldDoesNotExist
    
  4. from django.db.models import CharField, Field, ForeignObjectRel, ManyToManyField
    
  5. from django.db.models.options import EMPTY_RELATION_TREE, IMMUTABLE_WARNING
    
  6. from django.test import SimpleTestCase
    
  7. 
    
  8. from .models import (
    
  9.     AbstractPerson,
    
  10.     BasePerson,
    
  11.     Child,
    
  12.     CommonAncestor,
    
  13.     FirstParent,
    
  14.     Person,
    
  15.     ProxyPerson,
    
  16.     Relating,
    
  17.     Relation,
    
  18.     SecondParent,
    
  19. )
    
  20. from .results import TEST_RESULTS
    
  21. 
    
  22. 
    
  23. class OptionsBaseTests(SimpleTestCase):
    
  24.     def _map_related_query_names(self, res):
    
  25.         return tuple((o.name, m) for o, m in res)
    
  26. 
    
  27.     def _map_names(self, res):
    
  28.         return tuple((f.name, m) for f, m in res)
    
  29. 
    
  30.     def _model(self, current_model, field):
    
  31.         model = field.model._meta.concrete_model
    
  32.         return None if model == current_model else model
    
  33. 
    
  34.     def _details(self, current_model, relation):
    
  35.         direct = isinstance(relation, (Field, GenericForeignKey))
    
  36.         model = relation.model._meta.concrete_model
    
  37.         if model == current_model:
    
  38.             model = None
    
  39. 
    
  40.         field = relation if direct else relation.field
    
  41.         return (
    
  42.             relation,
    
  43.             model,
    
  44.             direct,
    
  45.             bool(field.many_to_many),
    
  46.         )  # many_to_many can be None
    
  47. 
    
  48. 
    
  49. class GetFieldsTests(OptionsBaseTests):
    
  50.     def test_get_fields_is_immutable(self):
    
  51.         msg = IMMUTABLE_WARNING % "get_fields()"
    
  52.         for _ in range(2):
    
  53.             # Running unit test twice to ensure both non-cached and cached result
    
  54.             # are immutable.
    
  55.             fields = Person._meta.get_fields()
    
  56.             with self.assertRaisesMessage(AttributeError, msg):
    
  57.                 fields += ["errors"]
    
  58. 
    
  59. 
    
  60. class LabelTests(OptionsBaseTests):
    
  61.     def test_label(self):
    
  62.         for model, expected_result in TEST_RESULTS["labels"].items():
    
  63.             self.assertEqual(model._meta.label, expected_result)
    
  64. 
    
  65.     def test_label_lower(self):
    
  66.         for model, expected_result in TEST_RESULTS["lower_labels"].items():
    
  67.             self.assertEqual(model._meta.label_lower, expected_result)
    
  68. 
    
  69. 
    
  70. class DataTests(OptionsBaseTests):
    
  71.     def test_fields(self):
    
  72.         for model, expected_result in TEST_RESULTS["fields"].items():
    
  73.             fields = model._meta.fields
    
  74.             self.assertEqual([f.attname for f in fields], expected_result)
    
  75. 
    
  76.     def test_local_fields(self):
    
  77.         def is_data_field(f):
    
  78.             return isinstance(f, Field) and not f.many_to_many
    
  79. 
    
  80.         for model, expected_result in TEST_RESULTS["local_fields"].items():
    
  81.             fields = model._meta.local_fields
    
  82.             self.assertEqual([f.attname for f in fields], expected_result)
    
  83.             for f in fields:
    
  84.                 self.assertEqual(f.model, model)
    
  85.                 self.assertTrue(is_data_field(f))
    
  86. 
    
  87.     def test_local_concrete_fields(self):
    
  88.         for model, expected_result in TEST_RESULTS["local_concrete_fields"].items():
    
  89.             fields = model._meta.local_concrete_fields
    
  90.             self.assertEqual([f.attname for f in fields], expected_result)
    
  91.             for f in fields:
    
  92.                 self.assertIsNotNone(f.column)
    
  93. 
    
  94. 
    
  95. class M2MTests(OptionsBaseTests):
    
  96.     def test_many_to_many(self):
    
  97.         for model, expected_result in TEST_RESULTS["many_to_many"].items():
    
  98.             fields = model._meta.many_to_many
    
  99.             self.assertEqual([f.attname for f in fields], expected_result)
    
  100.             for f in fields:
    
  101.                 self.assertTrue(f.many_to_many and f.is_relation)
    
  102. 
    
  103.     def test_many_to_many_with_model(self):
    
  104.         for model, expected_result in TEST_RESULTS["many_to_many_with_model"].items():
    
  105.             models = [self._model(model, field) for field in model._meta.many_to_many]
    
  106.             self.assertEqual(models, expected_result)
    
  107. 
    
  108. 
    
  109. class RelatedObjectsTests(OptionsBaseTests):
    
  110.     def key_name(self, r):
    
  111.         return r[0]
    
  112. 
    
  113.     def test_related_objects(self):
    
  114.         result_key = "get_all_related_objects_with_model"
    
  115.         for model, expected in TEST_RESULTS[result_key].items():
    
  116.             objects = [
    
  117.                 (field, self._model(model, field))
    
  118.                 for field in model._meta.get_fields()
    
  119.                 if field.auto_created and not field.concrete
    
  120.             ]
    
  121.             self.assertEqual(
    
  122.                 sorted(self._map_related_query_names(objects), key=self.key_name),
    
  123.                 sorted(expected, key=self.key_name),
    
  124.             )
    
  125. 
    
  126.     def test_related_objects_local(self):
    
  127.         result_key = "get_all_related_objects_with_model_local"
    
  128.         for model, expected in TEST_RESULTS[result_key].items():
    
  129.             objects = [
    
  130.                 (field, self._model(model, field))
    
  131.                 for field in model._meta.get_fields(include_parents=False)
    
  132.                 if field.auto_created and not field.concrete
    
  133.             ]
    
  134.             self.assertEqual(
    
  135.                 sorted(self._map_related_query_names(objects), key=self.key_name),
    
  136.                 sorted(expected, key=self.key_name),
    
  137.             )
    
  138. 
    
  139.     def test_related_objects_include_hidden(self):
    
  140.         result_key = "get_all_related_objects_with_model_hidden"
    
  141.         for model, expected in TEST_RESULTS[result_key].items():
    
  142.             objects = [
    
  143.                 (field, self._model(model, field))
    
  144.                 for field in model._meta.get_fields(include_hidden=True)
    
  145.                 if field.auto_created and not field.concrete
    
  146.             ]
    
  147.             self.assertEqual(
    
  148.                 sorted(self._map_names(objects), key=self.key_name),
    
  149.                 sorted(expected, key=self.key_name),
    
  150.             )
    
  151. 
    
  152.     def test_related_objects_include_hidden_local_only(self):
    
  153.         result_key = "get_all_related_objects_with_model_hidden_local"
    
  154.         for model, expected in TEST_RESULTS[result_key].items():
    
  155.             objects = [
    
  156.                 (field, self._model(model, field))
    
  157.                 for field in model._meta.get_fields(
    
  158.                     include_hidden=True, include_parents=False
    
  159.                 )
    
  160.                 if field.auto_created and not field.concrete
    
  161.             ]
    
  162.             self.assertEqual(
    
  163.                 sorted(self._map_names(objects), key=self.key_name),
    
  164.                 sorted(expected, key=self.key_name),
    
  165.             )
    
  166. 
    
  167. 
    
  168. class PrivateFieldsTests(OptionsBaseTests):
    
  169.     def test_private_fields(self):
    
  170.         for model, expected_names in TEST_RESULTS["private_fields"].items():
    
  171.             objects = model._meta.private_fields
    
  172.             self.assertEqual(sorted(f.name for f in objects), sorted(expected_names))
    
  173. 
    
  174. 
    
  175. class GetFieldByNameTests(OptionsBaseTests):
    
  176.     def test_get_data_field(self):
    
  177.         field_info = self._details(Person, Person._meta.get_field("data_abstract"))
    
  178.         self.assertEqual(field_info[1:], (BasePerson, True, False))
    
  179.         self.assertIsInstance(field_info[0], CharField)
    
  180. 
    
  181.     def test_get_m2m_field(self):
    
  182.         field_info = self._details(Person, Person._meta.get_field("m2m_base"))
    
  183.         self.assertEqual(field_info[1:], (BasePerson, True, True))
    
  184.         self.assertIsInstance(field_info[0], ManyToManyField)
    
  185. 
    
  186.     def test_get_related_object(self):
    
  187.         field_info = self._details(
    
  188.             Person, Person._meta.get_field("relating_baseperson")
    
  189.         )
    
  190.         self.assertEqual(field_info[1:], (BasePerson, False, False))
    
  191.         self.assertIsInstance(field_info[0], ForeignObjectRel)
    
  192. 
    
  193.     def test_get_related_m2m(self):
    
  194.         field_info = self._details(Person, Person._meta.get_field("relating_people"))
    
  195.         self.assertEqual(field_info[1:], (None, False, True))
    
  196.         self.assertIsInstance(field_info[0], ForeignObjectRel)
    
  197. 
    
  198.     def test_get_generic_relation(self):
    
  199.         field_info = self._details(
    
  200.             Person, Person._meta.get_field("generic_relation_base")
    
  201.         )
    
  202.         self.assertEqual(field_info[1:], (None, True, False))
    
  203.         self.assertIsInstance(field_info[0], GenericRelation)
    
  204. 
    
  205.     def test_get_fields_only_searches_forward_on_apps_not_ready(self):
    
  206.         opts = Person._meta
    
  207.         # If apps registry is not ready, get_field() searches over only
    
  208.         # forward fields.
    
  209.         opts.apps.models_ready = False
    
  210.         try:
    
  211.             # 'data_abstract' is a forward field, and therefore will be found
    
  212.             self.assertTrue(opts.get_field("data_abstract"))
    
  213.             msg = (
    
  214.                 "Person has no field named 'relating_baseperson'. The app "
    
  215.                 "cache isn't ready yet, so if this is an auto-created related "
    
  216.                 "field, it won't be available yet."
    
  217.             )
    
  218.             # 'data_abstract' is a reverse field, and will raise an exception
    
  219.             with self.assertRaisesMessage(FieldDoesNotExist, msg):
    
  220.                 opts.get_field("relating_baseperson")
    
  221.         finally:
    
  222.             opts.apps.models_ready = True
    
  223. 
    
  224. 
    
  225. class RelationTreeTests(SimpleTestCase):
    
  226.     all_models = (Relation, AbstractPerson, BasePerson, Person, ProxyPerson, Relating)
    
  227. 
    
  228.     def setUp(self):
    
  229.         apps.clear_cache()
    
  230. 
    
  231.     def test_clear_cache_clears_relation_tree(self):
    
  232.         # The apps.clear_cache is setUp() should have deleted all trees.
    
  233.         # Exclude abstract models that are not included in the Apps registry
    
  234.         # and have no cache.
    
  235.         all_models_with_cache = (m for m in self.all_models if not m._meta.abstract)
    
  236.         for m in all_models_with_cache:
    
  237.             self.assertNotIn("_relation_tree", m._meta.__dict__)
    
  238. 
    
  239.     def test_first_relation_tree_access_populates_all(self):
    
  240.         # On first access, relation tree should have populated cache.
    
  241.         self.assertTrue(self.all_models[0]._meta._relation_tree)
    
  242. 
    
  243.         # AbstractPerson does not have any relations, so relation_tree
    
  244.         # should just return an EMPTY_RELATION_TREE.
    
  245.         self.assertEqual(AbstractPerson._meta._relation_tree, EMPTY_RELATION_TREE)
    
  246. 
    
  247.         # All the other models should already have their relation tree
    
  248.         # in the internal __dict__ .
    
  249.         all_models_but_abstractperson = (
    
  250.             m for m in self.all_models if m is not AbstractPerson
    
  251.         )
    
  252.         for m in all_models_but_abstractperson:
    
  253.             self.assertIn("_relation_tree", m._meta.__dict__)
    
  254. 
    
  255.     def test_relations_related_objects(self):
    
  256.         # Testing non hidden related objects
    
  257.         self.assertEqual(
    
  258.             sorted(
    
  259.                 field.related_query_name()
    
  260.                 for field in Relation._meta._relation_tree
    
  261.                 if not field.remote_field.field.remote_field.is_hidden()
    
  262.             ),
    
  263.             sorted(
    
  264.                 [
    
  265.                     "fk_abstract_rel",
    
  266.                     "fk_base_rel",
    
  267.                     "fk_concrete_rel",
    
  268.                     "fo_abstract_rel",
    
  269.                     "fo_base_rel",
    
  270.                     "fo_concrete_rel",
    
  271.                     "m2m_abstract_rel",
    
  272.                     "m2m_base_rel",
    
  273.                     "m2m_concrete_rel",
    
  274.                 ]
    
  275.             ),
    
  276.         )
    
  277.         # Testing hidden related objects
    
  278.         self.assertEqual(
    
  279.             sorted(
    
  280.                 field.related_query_name() for field in BasePerson._meta._relation_tree
    
  281.             ),
    
  282.             sorted(
    
  283.                 [
    
  284.                     "+",
    
  285.                     "_model_meta_relating_basepeople_hidden_+",
    
  286.                     "BasePerson_following_abstract+",
    
  287.                     "BasePerson_following_abstract+",
    
  288.                     "BasePerson_following_base+",
    
  289.                     "BasePerson_following_base+",
    
  290.                     "BasePerson_friends_abstract+",
    
  291.                     "BasePerson_friends_abstract+",
    
  292.                     "BasePerson_friends_base+",
    
  293.                     "BasePerson_friends_base+",
    
  294.                     "BasePerson_m2m_abstract+",
    
  295.                     "BasePerson_m2m_base+",
    
  296.                     "Relating_basepeople+",
    
  297.                     "Relating_basepeople_hidden+",
    
  298.                     "followers_abstract",
    
  299.                     "followers_base",
    
  300.                     "friends_abstract_rel_+",
    
  301.                     "friends_base_rel_+",
    
  302.                     "person",
    
  303.                     "relating_basepeople",
    
  304.                     "relating_baseperson",
    
  305.                 ]
    
  306.             ),
    
  307.         )
    
  308.         self.assertEqual(
    
  309.             [
    
  310.                 field.related_query_name()
    
  311.                 for field in AbstractPerson._meta._relation_tree
    
  312.             ],
    
  313.             [],
    
  314.         )
    
  315. 
    
  316. 
    
  317. class ParentListTests(SimpleTestCase):
    
  318.     def test_get_parent_list(self):
    
  319.         self.assertEqual(CommonAncestor._meta.get_parent_list(), [])
    
  320.         self.assertEqual(FirstParent._meta.get_parent_list(), [CommonAncestor])
    
  321.         self.assertEqual(SecondParent._meta.get_parent_list(), [CommonAncestor])
    
  322.         self.assertEqual(
    
  323.             Child._meta.get_parent_list(), [FirstParent, SecondParent, CommonAncestor]
    
  324.         )
    
  325. 
    
  326. 
    
  327. class PropertyNamesTests(SimpleTestCase):
    
  328.     def test_person(self):
    
  329.         # Instance only descriptors don't appear in _property_names.
    
  330.         self.assertEqual(BasePerson().test_instance_only_descriptor, 1)
    
  331.         with self.assertRaisesMessage(AttributeError, "Instance only"):
    
  332.             AbstractPerson.test_instance_only_descriptor
    
  333.         self.assertEqual(
    
  334.             AbstractPerson._meta._property_names, frozenset(["pk", "test_property"])
    
  335.         )
    
  336. 
    
  337. 
    
  338. class ReturningFieldsTests(SimpleTestCase):
    
  339.     def test_pk(self):
    
  340.         self.assertEqual(Relation._meta.db_returning_fields, [Relation._meta.pk])
    
  341. 
    
  342. 
    
  343. class AbstractModelTests(SimpleTestCase):
    
  344.     def test_abstract_model_not_instantiated(self):
    
  345.         msg = "Abstract models cannot be instantiated."
    
  346.         with self.assertRaisesMessage(TypeError, msg):
    
  347.             AbstractPerson()