diff options
| author | Daniel Pyrathon <pirosb3@gmail.com> | 2015-01-06 19:16:35 -0500 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2015-01-06 19:25:12 -0500 |
| commit | fb48eb05816b1ac87d58696cdfe48be18c901f16 (patch) | |
| tree | 3d2e981b6f3fafdeb7310d0734fb148ebb7f6aef /tests | |
| parent | 749d23251bbd6564341405e6f8c1da129b8307e7 (diff) | |
Fixed #12663 -- Formalized the Model._meta API for retrieving fields.
Thanks to Russell Keith-Magee for mentoring this Google Summer of
Code 2014 project and everyone else who helped with the patch!
Diffstat (limited to 'tests')
| -rw-r--r-- | tests/backends/tests.py | 2 | ||||
| -rw-r--r-- | tests/basic/tests.py | 2 | ||||
| -rw-r--r-- | tests/fixtures/tests.py | 2 | ||||
| -rw-r--r-- | tests/generic_relations/tests.py | 3 | ||||
| -rw-r--r-- | tests/generic_relations_regress/tests.py | 2 | ||||
| -rw-r--r-- | tests/m2m_and_m2o/tests.py | 6 | ||||
| -rw-r--r-- | tests/many_to_one/tests.py | 4 | ||||
| -rw-r--r-- | tests/migrations/test_state.py | 4 | ||||
| -rw-r--r-- | tests/model_fields/models.py | 51 | ||||
| -rw-r--r-- | tests/model_fields/test_field_flags.py | 220 | ||||
| -rw-r--r-- | tests/model_fields/tests.py | 2 | ||||
| -rw-r--r-- | tests/model_meta/results.py | 796 | ||||
| -rw-r--r-- | tests/model_meta/test.py | 661 | ||||
| -rw-r--r-- | tests/model_meta/test_legacy.py | 166 | ||||
| -rw-r--r-- | tests/model_meta/tests.py | 247 | ||||
| -rw-r--r-- | tests/queries/tests.py | 2 | ||||
| -rw-r--r-- | tests/queryset_pickle/tests.py | 2 | ||||
| -rw-r--r-- | tests/schema/tests.py | 52 |
18 files changed, 1526 insertions, 698 deletions
diff --git a/tests/backends/tests.py b/tests/backends/tests.py index 7fbb57ba0c..9eeb90335c 100644 --- a/tests/backends/tests.py +++ b/tests/backends/tests.py @@ -1020,7 +1020,7 @@ class DBConstraintTestCase(TestCase): self.assertEqual(models.Object.objects.count(), 2) self.assertEqual(obj.related_objects.count(), 1) - intermediary_model = models.Object._meta.get_field_by_name("related_objects")[0].rel.through + intermediary_model = models.Object._meta.get_field("related_objects").rel.through intermediary_model.objects.create(from_object_id=obj.id, to_object_id=12345) self.assertEqual(obj.related_objects.count(), 1) self.assertEqual(intermediary_model.objects.count(), 2) diff --git a/tests/basic/tests.py b/tests/basic/tests.py index 74515047f5..3ba94d058d 100644 --- a/tests/basic/tests.py +++ b/tests/basic/tests.py @@ -776,7 +776,7 @@ class ModelRefreshTests(TestCase): class TestRelatedObjectDeprecation(TestCase): def test_field_related_deprecation(self): - field = SelfRef._meta.get_field_by_name('selfref')[0] + field = SelfRef._meta.get_field('selfref') with warnings.catch_warnings(record=True) as warns: warnings.simplefilter('always') self.assertIsInstance(field.related, ForeignObjectRel) diff --git a/tests/fixtures/tests.py b/tests/fixtures/tests.py index adef8ec5e5..0201693dba 100644 --- a/tests/fixtures/tests.py +++ b/tests/fixtures/tests.py @@ -3,6 +3,7 @@ from __future__ import unicode_literals import os import warnings +from django.apps import apps from django.contrib.sites.models import Site from django.core import management from django.db import connection, IntegrityError @@ -76,6 +77,7 @@ class FixtureLoadingTests(DumpDataAssertMixin, TestCase): ]) def test_loading_and_dumping(self): + apps.clear_cache() Site.objects.all().delete() # Load fixture 1. Single JSON file, with two objects. management.call_command('loaddata', 'fixture1.json', verbosity=0) diff --git a/tests/generic_relations/tests.py b/tests/generic_relations/tests.py index e7f7b02f5b..c6230b057e 100644 --- a/tests/generic_relations/tests.py +++ b/tests/generic_relations/tests.py @@ -403,7 +403,8 @@ class GenericRelationsTests(TestCase): self.assertEqual(tag.content_object.id, diamond.id) def test_query_content_type(self): - with six.assertRaisesRegex(self, FieldError, "^Cannot resolve keyword 'content_object' into field."): + msg = "Field 'content_object' does not generate an automatic reverse relation" + with self.assertRaisesMessage(FieldError, msg): TaggedItem.objects.get(content_object='') diff --git a/tests/generic_relations_regress/tests.py b/tests/generic_relations_regress/tests.py index 65afa9f298..88243bade0 100644 --- a/tests/generic_relations_regress/tests.py +++ b/tests/generic_relations_regress/tests.py @@ -260,7 +260,7 @@ class GenericRelationTests(TestCase): form = GenericRelationForm({'links': None}) self.assertTrue(form.is_valid()) form.save() - links = HasLinkThing._meta.get_field_by_name('links')[0] + links = HasLinkThing._meta.get_field('links') self.assertEqual(links.save_form_data_calls, 1) def test_ticket_22998(self): diff --git a/tests/m2m_and_m2o/tests.py b/tests/m2m_and_m2o/tests.py index e950a839d2..2317f62300 100644 --- a/tests/m2m_and_m2o/tests.py +++ b/tests/m2m_and_m2o/tests.py @@ -5,6 +5,12 @@ from .models import Issue, User, UnicodeReferenceModel class RelatedObjectTests(TestCase): + + def test_related_objects_have_name_attribute(self): + for field_name in ('test_issue_client', 'test_issue_cc'): + obj = User._meta.get_field(field_name) + self.assertEqual(field_name, obj.field.related_query_name()) + def test_m2m_and_m2o(self): r = User.objects.create(username="russell") g = User.objects.create(username="gustav") diff --git a/tests/many_to_one/tests.py b/tests/many_to_one/tests.py index 0195e5d2d8..e82d8eefe6 100644 --- a/tests/many_to_one/tests.py +++ b/tests/many_to_one/tests.py @@ -437,11 +437,11 @@ class ManyToOneTests(TestCase): expected_message = "Cannot resolve keyword 'notafield' into field. Choices are: %s" self.assertRaisesMessage(FieldError, - expected_message % ', '.join(Reporter._meta.get_all_field_names()), + expected_message % ', '.join(sorted(f.name for f in Reporter._meta.get_fields())), Article.objects.values_list, 'reporter__notafield') self.assertRaisesMessage(FieldError, - expected_message % ', '.join(['EXTRA'] + Article._meta.get_all_field_names()), + expected_message % ', '.join(['EXTRA'] + sorted(f.name for f in Article._meta.get_fields())), Article.objects.extra(select={'EXTRA': 'EXTRA_SELECT'}).values_list, 'notafield') diff --git a/tests/migrations/test_state.py b/tests/migrations/test_state.py index 6f510813af..e069649810 100644 --- a/tests/migrations/test_state.py +++ b/tests/migrations/test_state.py @@ -202,8 +202,8 @@ class StateTests(TestCase): )) new_apps = project_state.apps - self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("name")[0].max_length, 100) - self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field_by_name("hidden")[0].null, False) + self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field("name").max_length, 100) + self.assertEqual(new_apps.get_model("migrations", "Tag")._meta.get_field("hidden").null, False) self.assertEqual(len(new_apps.get_model("migrations", "SubTag")._meta.local_fields), 2) diff --git a/tests/model_fields/models.py b/tests/model_fields/models.py index 2a7bebc9dd..8927ae8830 100644 --- a/tests/model_fields/models.py +++ b/tests/model_fields/models.py @@ -8,6 +8,11 @@ except ImportError: Image = None from django.core.files.storage import FileSystemStorage +from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation +from django.contrib.contenttypes.models import ContentType +from django.db.models.fields.related import ( + ForeignObject, ForeignKey, ManyToManyField, OneToOneField, +) from django.db import models from django.db.models.fields.files import ImageFieldFile, ImageField from django.utils import six @@ -295,6 +300,52 @@ if Image: height_field='headshot_height', width_field='headshot_width') + +class AllFieldsModel(models.Model): + big_integer = models.BigIntegerField() + binary = models.BinaryField() + boolean = models.BooleanField(default=False) + char = models.CharField(max_length=10) + csv = models.CommaSeparatedIntegerField(max_length=10) + date = models.DateField() + datetime = models.DateTimeField() + decimal = models.DecimalField(decimal_places=2, max_digits=2) + duration = models.DurationField() + email = models.EmailField() + file_path = models.FilePathField() + floatf = models.FloatField() + integer = models.IntegerField() + ip_address = models.IPAddressField() + generic_ip = models.GenericIPAddressField() + null_boolean = models.NullBooleanField() + positive_integer = models.PositiveIntegerField() + positive_small_integer = models.PositiveSmallIntegerField() + slug = models.SlugField() + small_integer = models.SmallIntegerField() + text = models.TextField() + time = models.TimeField() + url = models.URLField() + uuid = models.UUIDField() + + fo = ForeignObject( + 'self', + from_fields=['abstract_non_concrete_id'], + to_fields=['id'], + related_name='reverse' + ) + fk = ForeignKey( + 'self', + related_name='reverse2' + ) + m2m = ManyToManyField('self') + oto = OneToOneField('self') + + object_id = models.PositiveIntegerField() + content_type = models.ForeignKey(ContentType) + gfk = GenericForeignKey() + gr = GenericRelation(DataModel) + + ############################################################################### diff --git a/tests/model_fields/test_field_flags.py b/tests/model_fields/test_field_flags.py new file mode 100644 index 0000000000..08a57db501 --- /dev/null +++ b/tests/model_fields/test_field_flags.py @@ -0,0 +1,220 @@ +from django import test + +from django.contrib.contenttypes.fields import ( + GenericForeignKey, GenericRelation, +) +from django.db import models +from django.db.models.fields.related import ( + ForeignObject, ForeignKey, OneToOneField, ManyToManyField, + ManyToOneRel, ForeignObjectRel, +) + +from .models import AllFieldsModel + + +NON_CONCRETE_FIELDS = ( + ForeignObject, + GenericForeignKey, + GenericRelation, +) + +NON_EDITABLE_FIELDS = ( + models.BinaryField, + GenericForeignKey, + GenericRelation, +) + +RELATION_FIELDS = ( + ForeignKey, + ForeignObject, + ManyToManyField, + OneToOneField, + GenericForeignKey, + GenericRelation, +) + +ONE_TO_MANY_CLASSES = { + ForeignObject, + ForeignKey, + GenericForeignKey, +} + +MANY_TO_ONE_CLASSES = { + ForeignObjectRel, + ManyToOneRel, + GenericRelation, +} + +MANY_TO_MANY_CLASSES = { + ManyToManyField, +} + +ONE_TO_ONE_CLASSES = { + OneToOneField, +} + +FLAG_PROPERTIES = ( + 'concrete', + 'editable', + 'is_relation', + 'model', + 'hidden', + 'one_to_many', + 'many_to_one', + 'many_to_many', + 'one_to_one', + 'related_model', +) + +FLAG_PROPERTIES_FOR_RELATIONS = ( + 'one_to_many', + 'many_to_one', + 'many_to_many', + 'one_to_one', +) + + +class FieldFlagsTests(test.TestCase): + @classmethod + def setUpClass(cls): + super(FieldFlagsTests, cls).setUpClass() + cls.fields = ( + list(AllFieldsModel._meta.fields) + + list(AllFieldsModel._meta.virtual_fields) + ) + + cls.all_fields = ( + cls.fields + + list(AllFieldsModel._meta.many_to_many) + + list(AllFieldsModel._meta.virtual_fields) + ) + + cls.fields_and_reverse_objects = ( + cls.all_fields + + list(AllFieldsModel._meta.related_objects) + ) + + def test_each_field_should_have_a_concrete_attribute(self): + self.assertTrue(all(f.concrete.__class__ == bool for f in self.fields)) + + def test_each_field_should_have_an_editable_attribute(self): + self.assertTrue(all(f.editable.__class__ == bool for f in self.all_fields)) + + def test_each_field_should_have_a_has_rel_attribute(self): + self.assertTrue(all(f.is_relation.__class__ == bool for f in self.all_fields)) + + def test_each_object_should_have_auto_created(self): + self.assertTrue( + all(f.auto_created.__class__ == bool + for f in self.fields_and_reverse_objects) + ) + + def test_non_concrete_fields(self): + for field in self.fields: + if type(field) in NON_CONCRETE_FIELDS: + self.assertFalse(field.concrete) + else: + self.assertTrue(field.concrete) + + def test_non_editable_fields(self): + for field in self.all_fields: + if type(field) in NON_EDITABLE_FIELDS: + self.assertFalse(field.editable) + else: + self.assertTrue(field.editable) + + def test_related_fields(self): + for field in self.all_fields: + if type(field) in RELATION_FIELDS: + self.assertTrue(field.is_relation) + else: + self.assertFalse(field.is_relation) + + def test_field_names_should_always_be_available(self): + for field in self.fields_and_reverse_objects: + self.assertTrue(field.name) + + def test_all_field_types_should_have_flags(self): + for field in self.fields_and_reverse_objects: + for flag in FLAG_PROPERTIES: + self.assertTrue(hasattr(field, flag), "Field %s does not have flag %s" % (field, flag)) + if field.is_relation: + true_cardinality_flags = sum( + getattr(field, flag) is True + for flag in FLAG_PROPERTIES_FOR_RELATIONS + ) + # If the field has a relation, there should be only one of the + # 4 cardinality flags available. + self.assertEqual(1, true_cardinality_flags) + + def test_cardinality_m2m(self): + m2m_type_fields = ( + f for f in self.all_fields + if f.is_relation and f.many_to_many + ) + # Test classes are what we expect + self.assertEqual(MANY_TO_MANY_CLASSES, {f.__class__ for f in m2m_type_fields}) + + # Ensure all m2m reverses are m2m + for field in m2m_type_fields: + reverse_field = field.rel + self.assertTrue(reverse_field.is_relation) + self.assertTrue(reverse_field.many_to_many) + self.assertTrue(reverse_field.related_model) + + def test_cardinality_o2m(self): + o2m_type_fields = [ + f for f in self.fields_and_reverse_objects + if f.is_relation and f.one_to_many + ] + # Test classes are what we expect + self.assertEqual(ONE_TO_MANY_CLASSES, {f.__class__ for f in o2m_type_fields}) + + # Ensure all o2m reverses are m2o + for field in o2m_type_fields: + if field.concrete: + reverse_field = field.rel + self.assertTrue(reverse_field.is_relation and reverse_field.many_to_one) + + def test_cardinality_m2o(self): + m2o_type_fields = [ + f for f in self.fields_and_reverse_objects + if f.is_relation and f.many_to_one + ] + # Test classes are what we expect + self.assertEqual(MANY_TO_ONE_CLASSES, {f.__class__ for f in m2o_type_fields}) + + # Ensure all m2o reverses are o2m + for obj in m2o_type_fields: + if hasattr(obj, 'field'): + reverse_field = obj.field + self.assertTrue(reverse_field.is_relation and reverse_field.one_to_many) + + def test_cardinality_o2o(self): + o2o_type_fields = [ + f for f in self.all_fields + if f.is_relation and f.one_to_one + ] + # Test classes are what we expect + self.assertEqual(ONE_TO_ONE_CLASSES, {f.__class__ for f in o2o_type_fields}) + + # Ensure all o2o reverses are o2o + for obj in o2o_type_fields: + if hasattr(obj, 'field'): + reverse_field = obj.field + self.assertTrue(reverse_field.is_relation and reverse_field.one_to_one) + + def test_hidden_flag(self): + incl_hidden = set(AllFieldsModel._meta.get_fields(include_hidden=True)) + no_hidden = set(AllFieldsModel._meta.get_fields()) + fields_that_should_be_hidden = (incl_hidden - no_hidden) + for f in incl_hidden: + self.assertEqual(f in fields_that_should_be_hidden, f.hidden) + + def test_model_and_reverse_model_should_equal_on_relations(self): + for field in AllFieldsModel._meta.get_fields(): + is_concrete_forward_field = field.concrete and field.related_model + if is_concrete_forward_field: + reverse_field = field.rel + self.assertEqual(field.model, reverse_field.related_model) + self.assertEqual(field.related_model, reverse_field.model) diff --git a/tests/model_fields/tests.py b/tests/model_fields/tests.py index e63cc007dd..d891645ca0 100644 --- a/tests/model_fields/tests.py +++ b/tests/model_fields/tests.py @@ -198,7 +198,7 @@ class ForeignKeyTests(test.TestCase): self.assertEqual(warnings, expected_warnings) def test_related_name_converted_to_text(self): - rel_name = Bar._meta.get_field_by_name('a')[0].rel.related_name + rel_name = Bar._meta.get_field('a').rel.related_name self.assertIsInstance(rel_name, six.text_type) diff --git a/tests/model_meta/results.py b/tests/model_meta/results.py new file mode 100644 index 0000000000..1efc49ed23 --- /dev/null +++ b/tests/model_meta/results.py @@ -0,0 +1,796 @@ +from .models import ( + AbstractPerson, BasePerson, Person, Relating, Relation, +) + +TEST_RESULTS = { + 'get_all_field_names': { + Person: [ + 'baseperson_ptr', + 'baseperson_ptr_id', + 'content_type_abstract', + 'content_type_abstract_id', + 'content_type_base', + 'content_type_base_id', + 'content_type_concrete', + 'content_type_concrete_id', + 'data_abstract', + 'data_base', + 'data_inherited', + 'data_not_concrete_abstract', + 'data_not_concrete_base', + 'data_not_concrete_inherited', + 'fk_abstract', + 'fk_abstract_id', + 'fk_base', + 'fk_base_id', + 'fk_inherited', + 'fk_inherited_id', + 'followers_abstract', + 'followers_base', + 'followers_concrete', + 'following_abstract', + 'following_base', + 'following_inherited', + 'friends_abstract', + 'friends_base', + 'friends_inherited', + 'generic_relation_abstract', + 'generic_relation_base', + 'generic_relation_concrete', + 'id', + 'm2m_abstract', + 'm2m_base', + 'm2m_inherited', + 'object_id_abstract', + 'object_id_base', + 'object_id_concrete', + 'relating_basepeople', + 'relating_baseperson', + 'relating_people', + 'relating_person', + ], + BasePerson: [ + 'content_type_abstract', + 'content_type_abstract_id', + 'content_type_base', + 'content_type_base_id', + 'data_abstract', + 'data_base', + 'data_not_concrete_abstract', + 'data_not_concrete_base', + 'fk_abstract', + 'fk_abstract_id', + 'fk_base', + 'fk_base_id', + 'followers_abstract', + 'followers_base', + 'following_abstract', + 'following_base', + 'friends_abstract', + 'friends_base', + 'generic_relation_abstract', + 'generic_relation_base', + 'id', + 'm2m_abstract', + 'm2m_base', + 'object_id_abstract', + 'object_id_base', + 'person', + 'relating_basepeople', + 'relating_baseperson' + ], + AbstractPerson: [ + 'content_type_abstract', + 'content_type_abstract_id', + 'data_abstract', + 'data_not_concrete_abstract', + 'fk_abstract', + 'fk_abstract_id', + 'following_abstract', + 'friends_abstract', + 'generic_relation_abstract', + 'm2m_abstract', + 'object_id_abstract', + ], + Relating: [ + 'basepeople', + 'basepeople_hidden', + 'baseperson', + 'baseperson_hidden', + 'baseperson_hidden_id', + 'baseperson_id', + 'id', + 'people', + 'people_hidden', + 'person', + 'person_hidden', + 'person_hidden_id', + 'person_id', + 'proxyperson', + 'proxyperson_hidden', + 'proxyperson_hidden_id', + 'proxyperson_id', + ], + }, + 'fields': { + Person: [ + 'id', + 'data_abstract', + 'fk_abstract_id', + 'data_not_concrete_abstract', + 'content_type_abstract_id', + 'object_id_abstract', + 'data_base', + 'fk_base_id', + 'data_not_concrete_base', + 'content_type_base_id', + 'object_id_base', + 'baseperson_ptr_id', + 'data_inherited', + 'fk_inherited_id', + 'data_not_concrete_inherited', + 'content_type_concrete_id', + 'object_id_concrete', + ], + BasePerson: [ + 'id', + 'data_abstract', + 'fk_abstract_id', + 'data_not_concrete_abstract', + 'content_type_abstract_id', + 'object_id_abstract', + 'data_base', + 'fk_base_id', + 'data_not_concrete_base', + 'content_type_base_id', + 'object_id_base', + ], + AbstractPerson: [ + 'data_abstract', + 'fk_abstract_id', + 'data_not_concrete_abstract', + 'content_type_abstract_id', + 'object_id_abstract', + ], + Relating: [ + 'id', + 'baseperson_id', + 'baseperson_hidden_id', + 'person_id', + 'person_hidden_id', + 'proxyperson_id', + 'proxyperson_hidden_id', + ], + }, + 'local_fields': { + Person: [ + 'baseperson_ptr_id', + 'data_inherited', + 'fk_inherited_id', + 'data_not_concrete_inherited', + 'content_type_concrete_id', + 'object_id_concrete', + ], + BasePerson: [ + 'id', + 'data_abstract', + 'fk_abstract_id', + 'data_not_concrete_abstract', + 'content_type_abstract_id', + 'object_id_abstract', + 'data_base', + 'fk_base_id', + 'data_not_concrete_base', + 'content_type_base_id', + 'object_id_base', + ], + AbstractPerson: [ + 'data_abstract', + 'fk_abstract_id', + 'data_not_concrete_abstract', + 'content_type_abstract_id', + 'object_id_abstract', + ], + Relating: [ + 'id', + 'baseperson_id', + 'baseperson_hidden_id', + 'person_id', + 'person_hidden_id', + 'proxyperson_id', + 'proxyperson_hidden_id', + ], + }, + 'local_concrete_fields': { + Person: [ + 'baseperson_ptr_id', + 'data_inherited', + 'fk_inherited_id', + 'content_type_concrete_id', + 'object_id_concrete', + ], + BasePerson: [ + 'id', + 'data_abstract', + 'fk_abstract_id', + 'content_type_abstract_id', + 'object_id_abstract', + 'data_base', + 'fk_base_id', + 'content_type_base_id', + 'object_id_base', + ], + AbstractPerson: [ + 'data_abstract', + 'fk_abstract_id', + 'content_type_abstract_id', + 'object_id_abstract', + ], + Relating: [ + 'id', + 'baseperson_id', + 'baseperson_hidden_id', + 'person_id', + 'person_hidden_id', + 'proxyperson_id', + 'proxyperson_hidden_id', + ], + }, + 'many_to_many': { + Person: [ + 'm2m_abstract', + 'friends_abstract', + 'following_abstract', + 'm2m_base', + 'friends_base', + 'following_base', + 'm2m_inherited', + 'friends_inherited', + 'following_inherited', + ], + BasePerson: [ + 'm2m_abstract', + 'friends_abstract', + 'following_abstract', + 'm2m_base', + 'friends_base', + 'following_base', + ], + AbstractPerson: [ + 'm2m_abstract', + 'friends_abstract', + 'following_abstract', + ], + Relating: [ + 'basepeople', + 'basepeople_hidden', + 'people', + 'people_hidden', + ], + }, + 'many_to_many_with_model': { + Person: [ + BasePerson, + BasePerson, + BasePerson, + BasePerson, + BasePerson, + BasePerson, + None, + None, + None, + ], + BasePerson: [ + None, + None, + None, + None, + None, + None, + ], + AbstractPerson: [ + None, + None, + None, + ], + Relating: [ + None, + None, + None, + None, + ], + }, + 'get_all_related_objects_with_model_legacy': { + Person: ( + ('relating_baseperson', BasePerson), + ('relating_person', None), + ), + BasePerson: ( + ('person', None), + ('relating_baseperson', None), + ), + Relation: ( + ('fk_abstract_rel', None), + ('fo_abstract_rel', None), + ('fk_base_rel', None), + ('fo_base_rel', None), + ('fk_concrete_rel', None), + ('fo_concrete_rel', None), + ), + }, + 'get_all_related_objects_with_model_hidden_local': { + Person: ( + ('+', None), + ('+', None), + ('Person_following_inherited+', None), + ('Person_following_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_m2m_inherited+', None), + ('Relating_people+', None), + ('Relating_people_hidden+', None), + ('followers_concrete', None), + ('friends_inherited_rel_+', None), + ('relating_people', None), + ('relating_person', None), + ), + BasePerson: ( + ('+', None), + ('+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_base+', None), + ('BasePerson_following_base+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Relating_basepeople+', None), + ('Relating_basepeople_hidden+', None), + ('followers_abstract', None), + ('followers_base', None), + ('friends_abstract_rel_+', None), + ('friends_base_rel_+', None), + ('person', None), + ('relating_basepeople', None), + ('relating_baseperson', None), + ), + Relation: ( + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Person_m2m_inherited+', None), + ('fk_abstract_rel', None), + ('fk_base_rel', None), + ('fk_concrete_rel', None), + ('fo_abstract_rel', None), + ('fo_base_rel', None), + ('fo_concrete_rel', None), + ('m2m_abstract_rel', None), + ('m2m_base_rel', None), + ('m2m_concrete_rel', None), + ), + }, + 'get_all_related_objects_with_model_hidden': { + Person: ( + ('+', BasePerson), + ('+', BasePerson), + ('+', None), + ('+', None), + ('BasePerson_following_abstract+', BasePerson), + ('BasePerson_following_abstract+', BasePerson), + ('BasePerson_following_base+', BasePerson), + ('BasePerson_following_base+', BasePerson), + ('BasePerson_friends_abstract+', BasePerson), + ('BasePerson_friends_abstract+', BasePerson), + ('BasePerson_friends_base+', BasePerson), + ('BasePerson_friends_base+', BasePerson), + ('BasePerson_m2m_abstract+', BasePerson), + ('BasePerson_m2m_base+', BasePerson), + ('Person_following_inherited+', None), + ('Person_following_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_m2m_inherited+', None), + ('Relating_basepeople+', BasePerson), + ('Relating_basepeople_hidden+', BasePerson), + ('Relating_people+', None), + ('Relating_people_hidden+', None), + ('followers_abstract', BasePerson), + ('followers_base', BasePerson), + ('followers_concrete', None), + ('friends_abstract_rel_+', BasePerson), + ('friends_base_rel_+', BasePerson), + ('friends_inherited_rel_+', None), + ('relating_basepeople', BasePerson), + ('relating_baseperson', BasePerson), + ('relating_people', None), + ('relating_person', None), + ), + BasePerson: ( + ('+', None), + ('+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_base+', None), + ('BasePerson_following_base+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Relating_basepeople+', None), + ('Relating_basepeople_hidden+', None), + ('followers_abstract', None), + ('followers_base', None), + ('friends_abstract_rel_+', None), + ('friends_base_rel_+', None), + ('person', None), + ('relating_basepeople', None), + ('relating_baseperson', None), + ), + Relation: ( + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Person_m2m_inherited+', None), + ('fk_abstract_rel', None), + ('fk_base_rel', None), + ('fk_concrete_rel', None), + ('fo_abstract_rel', None), + ('fo_base_rel', None), + ('fo_concrete_rel', None), + ('m2m_abstract_rel', None), + ('m2m_base_rel', None), + ('m2m_concrete_rel', None), + ), + }, + 'get_all_related_objects_with_model_local': { + Person: ( + ('followers_concrete', None), + ('relating_person', None), + ('relating_people', None), + ), + BasePerson: ( + ('followers_abstract', None), + ('followers_base', None), + ('person', None), + ('relating_baseperson', None), + ('relating_basepeople', None), + ), + Relation: ( + ('fk_abstract_rel', None), + ('fo_abstract_rel', None), + ('fk_base_rel', None), + ('fo_base_rel', None), + ('m2m_abstract_rel', None), + ('m2m_base_rel', None), + ('fk_concrete_rel', None), + ('fo_concrete_rel', None), + ('m2m_concrete_rel', None), + ), + }, + 'get_all_related_objects_with_model': { + Person: ( + ('followers_abstract', BasePerson), + ('followers_base', BasePerson), + ('relating_baseperson', BasePerson), + ('relating_basepeople', BasePerson), + ('followers_concrete', None), + ('relating_person', None), + ('relating_people', None), + ), + BasePerson: ( + ('followers_abstract', None), + ('followers_base', None), + ('person', None), + ('relating_baseperson', None), + ('relating_basepeople', None), + ), + Relation: ( + ('fk_abstract_rel', None), + ('fo_abstract_rel', None), + ('fk_base_rel', None), + ('fo_base_rel', None), + ('m2m_abstract_rel', None), + ('m2m_base_rel', None), + ('fk_concrete_rel', None), + ('fo_concrete_rel', None), + ('m2m_concrete_rel', None), + ), + }, + 'get_all_related_objects_with_model_local_legacy': { + Person: ( + ('relating_person', None), + ), + BasePerson: ( + ('person', None), + ('relating_baseperson', None) + ), + Relation: ( + ('fk_abstract_rel', None), + ('fo_abstract_rel', None), + ('fk_base_rel', None), + ('fo_base_rel', None), + ('fk_concrete_rel', None), + ('fo_concrete_rel', None), + ), + }, + 'get_all_related_objects_with_model_hidden_legacy': { + BasePerson: ( + ('+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_base+', None), + ('BasePerson_following_base+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Relating_basepeople+', None), + ('Relating_basepeople_hidden+', None), + ('person', None), + ('relating_baseperson', None), + ), + Person: ( + ('+', BasePerson), + ('+', None), + ('BasePerson_following_abstract+', BasePerson), + ('BasePerson_following_abstract+', BasePerson), + ('BasePerson_following_base+', BasePerson), + ('BasePerson_following_base+', BasePerson), + ('BasePerson_friends_abstract+', BasePerson), + ('BasePerson_friends_abstract+', BasePerson), + ('BasePerson_friends_base+', BasePerson), + ('BasePerson_friends_base+', BasePerson), + ('BasePerson_m2m_abstract+', BasePerson), + ('BasePerson_m2m_base+', BasePerson), + ('Person_following_inherited+', None), + ('Person_following_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_m2m_inherited+', None), + ('Relating_basepeople+', BasePerson), + ('Relating_basepeople_hidden+', BasePerson), + ('Relating_people+', None), + ('Relating_people_hidden+', None), + ('relating_baseperson', BasePerson), + ('relating_person', None), + ), + Relation: ( + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Person_m2m_inherited+', None), + ('fk_abstract_rel', None), + ('fk_base_rel', None), + ('fk_concrete_rel', None), + ('fo_abstract_rel', None), + ('fo_base_rel', None), + ('fo_concrete_rel', None), + ), + }, + 'get_all_related_objects_with_model_hidden_local_legacy': { + BasePerson: ( + ('+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_base+', None), + ('BasePerson_following_base+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Relating_basepeople+', None), + ('Relating_basepeople_hidden+', None), + ('person', None), + ('relating_baseperson', None), + ), + Person: ( + ('+', None), + ('Person_following_inherited+', None), + ('Person_following_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_m2m_inherited+', None), + ('Relating_people+', None), + ('Relating_people_hidden+', None), + ('relating_person', None), + ), + Relation: ( + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Person_m2m_inherited+', None), + ('fk_abstract_rel', None), + ('fk_base_rel', None), + ('fk_concrete_rel', None), + ('fo_abstract_rel', None), + ('fo_base_rel', None), + ('fo_concrete_rel', None), + ), + }, + 'get_all_related_objects_with_model_proxy_legacy': { + BasePerson: ( + ('person', None), + ('relating_baseperson', None), + ), + Person: ( + ('relating_baseperson', BasePerson), + ('relating_person', None), ('relating_proxyperson', None), + ), + Relation: ( + ('fk_abstract_rel', None), ('fo_abstract_rel', None), + ('fk_base_rel', None), ('fo_base_rel', None), + ('fk_concrete_rel', None), ('fo_concrete_rel', None), + ), + }, + 'get_all_related_objects_with_model_proxy_hidden_legacy': { + BasePerson: ( + ('+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_abstract+', None), + ('BasePerson_following_base+', None), + ('BasePerson_following_base+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_abstract+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_friends_base+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Relating_basepeople+', None), + ('Relating_basepeople_hidden+', None), + ('person', None), + ('relating_baseperson', None), + ), + Person: ( + ('+', BasePerson), + ('+', None), + ('+', None), + ('BasePerson_following_abstract+', BasePerson), + ('BasePerson_following_abstract+', BasePerson), + ('BasePerson_following_base+', BasePerson), + ('BasePerson_following_base+', BasePerson), + ('BasePerson_friends_abstract+', BasePerson), + ('BasePerson_friends_abstract+', BasePerson), + ('BasePerson_friends_base+', BasePerson), + ('BasePerson_friends_base+', BasePerson), + ('BasePerson_m2m_abstract+', BasePerson), + ('BasePerson_m2m_base+', BasePerson), + ('Person_following_inherited+', None), + ('Person_following_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_friends_inherited+', None), + ('Person_m2m_inherited+', None), + ('Relating_basepeople+', BasePerson), + ('Relating_basepeople_hidden+', BasePerson), + ('Relating_people+', None), + ('Relating_people_hidden+', None), + ('relating_baseperson', BasePerson), + ('relating_person', None), + ('relating_proxyperson', None), + ), + Relation: ( + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('+', None), + ('BasePerson_m2m_abstract+', None), + ('BasePerson_m2m_base+', None), + ('Person_m2m_inherited+', None), + ('fk_abstract_rel', None), + ('fk_base_rel', None), + ('fk_concrete_rel', None), + ('fo_abstract_rel', None), + ('fo_base_rel', None), + ('fo_concrete_rel', None), + ), + }, + 'get_all_related_many_to_many_with_model_legacy': { + BasePerson: ( + ('friends_abstract_rel_+', None), + ('followers_abstract', None), + ('friends_base_rel_+', None), + ('followers_base', None), + ('relating_basepeople', None), + ('+', None), + ), + Person: ( + ('friends_abstract_rel_+', BasePerson), + ('followers_abstract', BasePerson), + ('friends_base_rel_+', BasePerson), + ('followers_base', BasePerson), + ('relating_basepeople', BasePerson), + ('+', BasePerson), + ('friends_inherited_rel_+', None), + ('followers_concrete', None), + ('relating_people', None), + ('+', None), + ), + Relation: ( + ('m2m_abstract_rel', None), + ('m2m_base_rel', None), + ('m2m_concrete_rel', None), + ), + }, + 'get_all_related_many_to_many_local_legacy': { + BasePerson: [ + 'friends_abstract_rel_+', + 'followers_abstract', + 'friends_base_rel_+', + 'followers_base', + 'relating_basepeople', + '+', + ], + Person: [ + 'friends_inherited_rel_+', + 'followers_concrete', + 'relating_people', + '+', + ], + Relation: [ + 'm2m_abstract_rel', + 'm2m_base_rel', + 'm2m_concrete_rel', + ], + }, + 'virtual_fields': { + AbstractPerson: [ + 'generic_relation_abstract', + 'content_object_abstract', + ], + BasePerson: [ + 'generic_relation_base', + 'content_object_base', + 'generic_relation_abstract', + 'content_object_abstract', + ], + Person: [ + 'content_object_concrete', + 'generic_relation_concrete', + 'generic_relation_base', + 'content_object_base', + 'generic_relation_abstract', + 'content_object_abstract', + ], + }, +} diff --git a/tests/model_meta/test.py b/tests/model_meta/test.py deleted file mode 100644 index ea861d5ad5..0000000000 --- a/tests/model_meta/test.py +++ /dev/null @@ -1,661 +0,0 @@ -from django import test -from django.contrib.contenttypes.fields import GenericRelation -from django.core.exceptions import FieldDoesNotExist -from django.db.models.fields import related, CharField, Field - -from .models import ( - AbstractPerson, BasePerson, Person, Relating, Relation -) - -TEST_RESULTS = { - 'fields': { - Person: [ - 'id', - 'data_abstract', - 'fk_abstract_id', - 'data_not_concrete_abstract', - 'content_type_abstract_id', - 'object_id_abstract', - 'data_base', - 'fk_base_id', - 'data_not_concrete_base', - 'content_type_base_id', - 'object_id_base', - 'baseperson_ptr_id', - 'data_inherited', - 'fk_inherited_id', - 'data_not_concrete_inherited', - 'content_type_concrete_id', - 'object_id_concrete', - ], - BasePerson: [ - 'id', - 'data_abstract', - 'fk_abstract_id', - 'data_not_concrete_abstract', - 'content_type_abstract_id', - 'object_id_abstract', - 'data_base', - 'fk_base_id', - 'data_not_concrete_base', - 'content_type_base_id', - 'object_id_base', - ], - AbstractPerson: [ - 'data_abstract', - 'fk_abstract_id', - 'data_not_concrete_abstract', - 'content_type_abstract_id', - 'object_id_abstract', - ], - Relating: [ - 'id', - 'baseperson_id', - 'baseperson_hidden_id', - 'person_id', - 'person_hidden_id', - 'proxyperson_id', - 'proxyperson_hidden_id', - ], - }, - 'local_fields': { - Person: [ - 'baseperson_ptr_id', - 'data_inherited', - 'fk_inherited_id', - 'data_not_concrete_inherited', - 'content_type_concrete_id', - 'object_id_concrete', - ], - BasePerson: [ - 'id', - 'data_abstract', - 'fk_abstract_id', - 'data_not_concrete_abstract', - 'content_type_abstract_id', - 'object_id_abstract', - 'data_base', - 'fk_base_id', - 'data_not_concrete_base', - 'content_type_base_id', - 'object_id_base', - ], - AbstractPerson: [ - 'data_abstract', - 'fk_abstract_id', - 'data_not_concrete_abstract', - 'content_type_abstract_id', - 'object_id_abstract', - ], - Relating: [ - 'id', - 'baseperson_id', - 'baseperson_hidden_id', - 'person_id', - 'person_hidden_id', - 'proxyperson_id', - 'proxyperson_hidden_id', - ], - }, - 'local_concrete_fields': { - Person: [ - 'baseperson_ptr_id', - 'data_inherited', - 'fk_inherited_id', - 'content_type_concrete_id', - 'object_id_concrete', - ], - BasePerson: [ - 'id', - 'data_abstract', - 'fk_abstract_id', - 'content_type_abstract_id', - 'object_id_abstract', - 'data_base', - 'fk_base_id', - 'content_type_base_id', - 'object_id_base', - ], - AbstractPerson: [ - 'data_abstract', - 'fk_abstract_id', - 'content_type_abstract_id', - 'object_id_abstract', - ], - Relating: [ - 'id', - 'baseperson_id', - 'baseperson_hidden_id', - 'person_id', - 'person_hidden_id', - 'proxyperson_id', - 'proxyperson_hidden_id', - ], - }, - 'many_to_many': { - Person: [ - 'm2m_abstract', - 'friends_abstract', - 'following_abstract', - 'm2m_base', - 'friends_base', - 'following_base', - 'm2m_inherited', - 'friends_inherited', - 'following_inherited', - ], - BasePerson: [ - 'm2m_abstract', - 'friends_abstract', - 'following_abstract', - 'm2m_base', - 'friends_base', - 'following_base', - ], - AbstractPerson: [ - 'm2m_abstract', - 'friends_abstract', - 'following_abstract', - ], - Relating: [ - 'basepeople', - 'basepeople_hidden', - 'people', - 'people_hidden', - ], - }, - 'many_to_many_with_model': { - Person: [ - BasePerson, - BasePerson, - BasePerson, - BasePerson, - BasePerson, - BasePerson, - None, - None, - None, - ], - BasePerson: [ - None, - None, - None, - None, - None, - None, - ], - AbstractPerson: [ - None, - None, - None, - ], - Relating: [ - None, - None, - None, - None, - ], - }, - 'get_all_related_objects_with_model': { - Person: ( - ('relating_baseperson', BasePerson), - ('relating_person', None), - ), - BasePerson: ( - ('person', None), - ('relating_baseperson', None), - ), - Relation: ( - ('fk_abstract_rel', None), - ('fo_abstract_rel', None), - ('fk_base_rel', None), - ('fo_base_rel', None), - ('fk_concrete_rel', None), - ('fo_concrete_rel', None), - ), - }, - 'get_all_related_objects_with_model_local': { - Person: ( - ('relating_person', None), - ), - BasePerson: ( - ('person', None), - ('relating_baseperson', None) - ), - Relation: ( - ('fk_abstract_rel', None), - ('fo_abstract_rel', None), - ('fk_base_rel', None), - ('fo_base_rel', None), - ('fk_concrete_rel', None), - ('fo_concrete_rel', None), - ), - }, - 'get_all_related_objects_with_model_hidden': { - BasePerson: ( - ('model_meta.baseperson_friends_base', None), - ('model_meta.baseperson_friends_base', None), - ('model_meta.baseperson_m2m_base', None), - ('model_meta.baseperson_following_base', None), - ('model_meta.baseperson_following_base', None), - ('model_meta.baseperson_m2m_abstract', None), - ('model_meta.baseperson_friends_abstract', None), - ('model_meta.baseperson_friends_abstract', None), - ('model_meta.baseperson_following_abstract', None), - ('model_meta.baseperson_following_abstract', None), - ('model_meta.person', None), - ('model_meta.relating_basepeople', None), - ('model_meta.relating_basepeople_hidden', None), - ('model_meta.relating', None), - ('model_meta.relating', None), - ), - Person: ( - ('model_meta.baseperson_friends_base', BasePerson), - ('model_meta.baseperson_friends_base', BasePerson), - ('model_meta.baseperson_m2m_base', BasePerson), - ('model_meta.baseperson_following_base', BasePerson), - ('model_meta.baseperson_following_base', BasePerson), - ('model_meta.baseperson_m2m_abstract', BasePerson), - ('model_meta.baseperson_friends_abstract', BasePerson), - ('model_meta.baseperson_friends_abstract', BasePerson), - ('model_meta.baseperson_following_abstract', BasePerson), - ('model_meta.baseperson_following_abstract', BasePerson), - ('model_meta.relating_basepeople', BasePerson), - ('model_meta.relating_basepeople_hidden', BasePerson), - ('model_meta.relating', BasePerson), - ('model_meta.relating', BasePerson), - ('model_meta.person_m2m_inherited', None), - ('model_meta.person_friends_inherited', None), - ('model_meta.person_friends_inherited', None), - ('model_meta.person_following_inherited', None), - ('model_meta.person_following_inherited', None), - ('model_meta.relating_people', None), - ('model_meta.relating_people_hidden', None), - ('model_meta.relating', None), - ('model_meta.relating', None), - ), - Relation: ( - ('model_meta.baseperson_m2m_base', None), - ('model_meta.baseperson_m2m_abstract', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.person_m2m_inherited', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.proxyperson', None), - ('model_meta.proxyperson', None), - ('model_meta.proxyperson', None), - ), - }, - 'get_all_related_objects_with_model_hidden_local': { - BasePerson: ( - ('model_meta.baseperson_friends_base', None), - ('model_meta.baseperson_friends_base', None), - ('model_meta.baseperson_m2m_base', None), - ('model_meta.baseperson_following_base', None), - ('model_meta.baseperson_following_base', None), - ('model_meta.baseperson_m2m_abstract', None), - ('model_meta.baseperson_friends_abstract', None), - ('model_meta.baseperson_friends_abstract', None), - ('model_meta.baseperson_following_abstract', None), - ('model_meta.baseperson_following_abstract', None), - ('model_meta.person', None), - ('model_meta.relating_basepeople', None), - ('model_meta.relating_basepeople_hidden', None), - ('model_meta.relating', None), - ('model_meta.relating', None), - ), - Person: ( - ('model_meta.person_m2m_inherited', None), - ('model_meta.person_friends_inherited', None), - ('model_meta.person_friends_inherited', None), - ('model_meta.person_following_inherited', None), - ('model_meta.person_following_inherited', None), - ('model_meta.relating_people', None), - ('model_meta.relating_people_hidden', None), - ('model_meta.relating', None), - ('model_meta.relating', None), - ), - Relation: ( - ('model_meta.baseperson_m2m_base', None), - ('model_meta.baseperson_m2m_abstract', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.person_m2m_inherited', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.proxyperson', None), - ('model_meta.proxyperson', None), - ('model_meta.proxyperson', None), - ), - }, - 'get_all_related_objects_with_model_proxy': { - BasePerson: ( - ('person', None), - ('relating_baseperson', None), - ), - Person: ( - ('relating_baseperson', BasePerson), - ('relating_person', None), ('relating_proxyperson', None), - ), - Relation: ( - ('fk_abstract_rel', None), ('fo_abstract_rel', None), - ('fk_base_rel', None), ('fo_base_rel', None), - ('fk_concrete_rel', None), ('fo_concrete_rel', None), - ), - }, - 'get_all_related_objects_with_model_proxy_hidden': { - BasePerson: ( - ('model_meta.baseperson_friends_base', None), - ('model_meta.baseperson_friends_base', None), - ('model_meta.baseperson_m2m_base', None), - ('model_meta.baseperson_following_base', None), - ('model_meta.baseperson_following_base', None), - ('model_meta.baseperson_m2m_abstract', None), - ('model_meta.baseperson_friends_abstract', None), - ('model_meta.baseperson_friends_abstract', None), - ('model_meta.baseperson_following_abstract', None), - ('model_meta.baseperson_following_abstract', None), - ('model_meta.person', None), - ('model_meta.relating_basepeople', None), - ('model_meta.relating_basepeople_hidden', None), - ('model_meta.relating', None), - ('model_meta.relating', None), - ), - Person: ( - ('model_meta.baseperson_friends_base', BasePerson), - ('model_meta.baseperson_friends_base', BasePerson), - ('model_meta.baseperson_m2m_base', BasePerson), - ('model_meta.baseperson_following_base', BasePerson), - ('model_meta.baseperson_following_base', BasePerson), - ('model_meta.baseperson_m2m_abstract', BasePerson), - ('model_meta.baseperson_friends_abstract', BasePerson), - ('model_meta.baseperson_friends_abstract', BasePerson), - ('model_meta.baseperson_following_abstract', BasePerson), - ('model_meta.baseperson_following_abstract', BasePerson), - ('model_meta.relating_basepeople', BasePerson), - ('model_meta.relating_basepeople_hidden', BasePerson), - ('model_meta.relating', BasePerson), - ('model_meta.relating', BasePerson), - ('model_meta.person_m2m_inherited', None), - ('model_meta.person_friends_inherited', None), - ('model_meta.person_friends_inherited', None), - ('model_meta.person_following_inherited', None), - ('model_meta.person_following_inherited', None), - ('model_meta.relating_people', None), - ('model_meta.relating_people_hidden', None), - ('model_meta.relating', None), - ('model_meta.relating', None), - ('model_meta.relating', None), - ('model_meta.relating', None), - ), - Relation: ( - ('model_meta.baseperson_m2m_base', None), - ('model_meta.baseperson_m2m_abstract', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.baseperson', None), - ('model_meta.person_m2m_inherited', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.person', None), - ('model_meta.proxyperson', None), - ('model_meta.proxyperson', None), - ('model_meta.proxyperson', None), - ), - }, - 'get_all_related_many_to_many_with_model': { - BasePerson: ( - ('friends_abstract_rel_+', None), - ('followers_abstract', None), - ('friends_base_rel_+', None), - ('followers_base', None), - ('relating_basepeople', None), - ('+', None), - ), - Person: ( - ('friends_abstract_rel_+', BasePerson), - ('followers_abstract', BasePerson), - ('friends_base_rel_+', BasePerson), - ('followers_base', BasePerson), - ('relating_basepeople', BasePerson), - ('+', BasePerson), - ('friends_inherited_rel_+', None), - ('followers_concrete', None), - ('relating_people', None), - ('+', None), - ), - Relation: ( - ('m2m_abstract_rel', None), - ('m2m_base_rel', None), - ('m2m_concrete_rel', None), - ), - }, - 'get_all_related_many_to_many_local': { - BasePerson: [ - 'friends_abstract_rel_+', - 'followers_abstract', - 'friends_base_rel_+', - 'followers_base', - 'relating_basepeople', - '+', - ], - Person: [ - 'friends_inherited_rel_+', - 'followers_concrete', - 'relating_people', - '+', - ], - Relation: [ - 'm2m_abstract_rel', - 'm2m_base_rel', - 'm2m_concrete_rel', - ], - }, - 'virtual_fields': { - AbstractPerson: [ - 'generic_relation_abstract', - 'content_object_abstract', - ], - BasePerson: [ - 'generic_relation_base', - 'content_object_base', - 'generic_relation_abstract', - 'content_object_abstract', - ], - Person: [ - 'content_object_concrete', - 'generic_relation_concrete', - 'generic_relation_base', - 'content_object_base', - 'generic_relation_abstract', - 'content_object_abstract', - ], - }, -} - - -class OptionsBaseTests(test.TestCase): - - def _map_rq_names(self, res): - return tuple((o.field.related_query_name(), m) for o, m in res) - - def _map_names(self, res): - return tuple((f.name, m) for f, m in res) - - -class DataTests(OptionsBaseTests): - - def test_fields(self): - for model, expected_result in TEST_RESULTS['fields'].items(): - fields = model._meta.fields - self.assertEqual([f.attname for f in fields], expected_result) - - def test_local_fields(self): - is_data_field = lambda f: isinstance(f, Field) and not isinstance(f, related.ManyToManyField) - - for model, expected_result in TEST_RESULTS['local_fields'].items(): - fields = model._meta.local_fields - self.assertEqual([f.attname for f in fields], expected_result) - self.assertTrue(all([f.model is model for f in fields])) - self.assertTrue(all([is_data_field(f) for f in fields])) - - def test_local_concrete_fields(self): - for model, expected_result in TEST_RESULTS['local_concrete_fields'].items(): - fields = model._meta.local_concrete_fields - self.assertEqual([f.attname for f in fields], expected_result) - self.assertTrue(all([f.column is not None for f in fields])) - - -class M2MTests(OptionsBaseTests): - - def test_many_to_many(self): - for model, expected_result in TEST_RESULTS['many_to_many'].items(): - fields = model._meta.many_to_many - self.assertEqual([f.attname for f in fields], expected_result) - self.assertTrue(all([isinstance(f.rel, related.ManyToManyRel) for f in fields])) - - def test_many_to_many_with_model(self): - for model, expected_result in TEST_RESULTS['many_to_many_with_model'].items(): - models = [model for field, model in model._meta.get_m2m_with_model()] - self.assertEqual(models, expected_result) - - -class RelatedObjectsTests(OptionsBaseTests): - def setUp(self): - self.key_name = lambda r: r[0] - - def test_related_objects(self): - result_key = 'get_all_related_objects_with_model' - for model, expected in TEST_RESULTS[result_key].items(): - objects = model._meta.get_all_related_objects_with_model() - self.assertEqual(self._map_rq_names(objects), expected) - - def test_related_objects_local(self): - result_key = 'get_all_related_objects_with_model_local' - for model, expected in TEST_RESULTS[result_key].items(): - objects = model._meta.get_all_related_objects_with_model(local_only=True) - self.assertEqual(self._map_rq_names(objects), expected) - - def test_related_objects_include_hidden(self): - result_key = 'get_all_related_objects_with_model_hidden' - for model, expected in TEST_RESULTS[result_key].items(): - objects = model._meta.get_all_related_objects_with_model(include_hidden=True) - self.assertEqual( - sorted(self._map_names(objects), key=self.key_name), - sorted(expected, key=self.key_name) - ) - - def test_related_objects_include_hidden_local_only(self): - result_key = 'get_all_related_objects_with_model_hidden_local' - for model, expected in TEST_RESULTS[result_key].items(): - objects = model._meta.get_all_related_objects_with_model( - include_hidden=True, local_only=True) - self.assertEqual( - sorted(self._map_names(objects), key=self.key_name), - sorted(expected, key=self.key_name) - ) - - def test_related_objects_proxy(self): - result_key = 'get_all_related_objects_with_model_proxy' - for model, expected in TEST_RESULTS[result_key].items(): - objects = model._meta.get_all_related_objects_with_model( - include_proxy_eq=True) - self.assertEqual(self._map_rq_names(objects), expected) - - def test_related_objects_proxy_hidden(self): - result_key = 'get_all_related_objects_with_model_proxy_hidden' - for model, expected in TEST_RESULTS[result_key].items(): - objects = model._meta.get_all_related_objects_with_model( - include_proxy_eq=True, include_hidden=True) - self.assertEqual( - sorted(self._map_names(objects), key=self.key_name), - sorted(expected, key=self.key_name) - ) - - -class RelatedM2MTests(OptionsBaseTests): - - def test_related_m2m_with_model(self): - result_key = 'get_all_related_many_to_many_with_model' - for model, expected in TEST_RESULTS[result_key].items(): - objects = model._meta.get_all_related_m2m_objects_with_model() - self.assertEqual(self._map_rq_names(objects), expected) - - def test_related_m2m_local_only(self): - result_key = 'get_all_related_many_to_many_local' - for model, expected in TEST_RESULTS[result_key].items(): - objects = model._meta.get_all_related_many_to_many_objects(local_only=True) - self.assertEqual([o.field.related_query_name() for o in objects], expected) - - def test_related_m2m_asymmetrical(self): - m2m = Person._meta.many_to_many - self.assertIn('following_base', [f.attname for f in m2m]) - related_m2m = Person._meta.get_all_related_many_to_many_objects() - self.assertIn('followers_base', [o.field.related_query_name() for o in related_m2m]) - - def test_related_m2m_symmetrical(self): - m2m = Person._meta.many_to_many - self.assertIn('friends_base', [f.attname for f in m2m]) - related_m2m = Person._meta.get_all_related_many_to_many_objects() - self.assertIn('friends_inherited_rel_+', [o.field.related_query_name() for o in related_m2m]) - - -class VirtualFieldsTests(OptionsBaseTests): - - def test_virtual_fields(self): - for model, expected_names in TEST_RESULTS['virtual_fields'].items(): - objects = model._meta.virtual_fields - self.assertEqual(sorted([f.name for f in objects]), sorted(expected_names)) - - -class GetFieldByNameTests(OptionsBaseTests): - - def test_get_data_field(self): - field_info = Person._meta.get_field_by_name('data_abstract') - self.assertEqual(field_info[1:], (BasePerson, True, False)) - self.assertIsInstance(field_info[0], CharField) - - def test_get_m2m_field(self): - field_info = Person._meta.get_field_by_name('m2m_base') - self.assertEqual(field_info[1:], (BasePerson, True, True)) - self.assertIsInstance(field_info[0], related.ManyToManyField) - - def test_get_related_object(self): - field_info = Person._meta.get_field_by_name('relating_baseperson') - self.assertEqual(field_info[1:], (BasePerson, False, False)) - self.assertIsInstance(field_info[0], related.ForeignObjectRel) - - def test_get_related_m2m(self): - field_info = Person._meta.get_field_by_name('relating_people') - self.assertEqual(field_info[1:], (None, False, True)) - self.assertIsInstance(field_info[0], related.ForeignObjectRel) - - def test_get_generic_foreign_key(self): - # For historic reasons generic foreign keys aren't available. - with self.assertRaises(FieldDoesNotExist): - Person._meta.get_field_by_name('content_object_base') - - def test_get_generic_relation(self): - field_info = Person._meta.get_field_by_name('generic_relation_base') - self.assertEqual(field_info[1:], (None, True, False)) - self.assertIsInstance(field_info[0], GenericRelation) diff --git a/tests/model_meta/test_legacy.py b/tests/model_meta/test_legacy.py new file mode 100644 index 0000000000..60bfb1641f --- /dev/null +++ b/tests/model_meta/test_legacy.py @@ -0,0 +1,166 @@ +import warnings + +from django import test +from django.contrib.contenttypes.fields import GenericRelation +from django.core.exceptions import FieldDoesNotExist +from django.db.models.fields import related, CharField +from django.utils.deprecation import RemovedInDjango20Warning + +from .models import BasePerson, Person +from .results import TEST_RESULTS + + +class OptionsBaseTests(test.TestCase): + + def _map_related_query_names(self, res): + return tuple((o.field.related_query_name(), m) for o, m in res) + + def _map_names(self, res): + return tuple((f.name, m) for f, m in res) + + +class M2MTests(OptionsBaseTests): + + def test_many_to_many_with_model(self): + for model, expected_result in TEST_RESULTS['many_to_many_with_model'].items(): + with warnings.catch_warnings(record=True) as warning: + warnings.simplefilter("always") + models = [model for field, model in model._meta.get_m2m_with_model()] + self.assertEqual([RemovedInDjango20Warning], [w.message.__class__ for w in warning]) + self.assertEqual(models, expected_result) + + +@test.ignore_warnings(category=RemovedInDjango20Warning) +class RelatedObjectsTests(OptionsBaseTests): + key_name = lambda self, r: r[0] + + def test_related_objects(self): + result_key = 'get_all_related_objects_with_model_legacy' + for model, expected in TEST_RESULTS[result_key].items(): + objects = model._meta.get_all_related_objects_with_model() + self.assertEqual(self._map_related_query_names(objects), expected) + + def test_related_objects_local(self): + result_key = 'get_all_related_objects_with_model_local_legacy' + for model, expected in TEST_RESULTS[result_key].items(): + objects = model._meta.get_all_related_objects_with_model(local_only=True) + self.assertEqual(self._map_related_query_names(objects), expected) + + def test_related_objects_include_hidden(self): + result_key = 'get_all_related_objects_with_model_hidden_legacy' + for model, expected in TEST_RESULTS[result_key].items(): + objects = model._meta.get_all_related_objects_with_model(include_hidden=True) + self.assertEqual( + sorted(self._map_names(objects), key=self.key_name), + sorted(expected, key=self.key_name) + ) + + def test_related_objects_include_hidden_local_only(self): + result_key = 'get_all_related_objects_with_model_hidden_local_legacy' + for model, expected in TEST_RESULTS[result_key].items(): + objects = model._meta.get_all_related_objects_with_model( + include_hidden=True, local_only=True) + self.assertEqual( + sorted(self._map_names(objects), key=self.key_name), + sorted(expected, key=self.key_name) + ) + + def test_related_objects_proxy(self): + result_key = 'get_all_related_objects_with_model_proxy_legacy' + for model, expected in TEST_RESULTS[result_key].items(): + objects = model._meta.get_all_related_objects_with_model( + include_proxy_eq=True) + self.assertEqual(self._map_related_query_names(objects), expected) + + def test_related_objects_proxy_hidden(self): + result_key = 'get_all_related_objects_with_model_proxy_hidden_legacy' + for model, expected in TEST_RESULTS[result_key].items(): + objects = model._meta.get_all_related_objects_with_model( + include_proxy_eq=True, include_hidden=True) + self.assertEqual( + sorted(self._map_names(objects), key=self.key_name), + sorted(expected, key=self.key_name) + ) + + +@test.ignore_warnings(category=RemovedInDjango20Warning) +class RelatedM2MTests(OptionsBaseTests): + + def test_related_m2m_with_model(self): + result_key = 'get_all_related_many_to_many_with_model_legacy' + for model, expected in TEST_RESULTS[result_key].items(): + objects = model._meta.get_all_related_m2m_objects_with_model() + self.assertEqual(self._map_related_query_names(objects), expected) + + def test_related_m2m_local_only(self): + result_key = 'get_all_related_many_to_many_local_legacy' + for model, expected in TEST_RESULTS[result_key].items(): + objects = model._meta.get_all_related_many_to_many_objects(local_only=True) + self.assertEqual([o.field.related_query_name() for o in objects], expected) + + def test_related_m2m_asymmetrical(self): + m2m = Person._meta.many_to_many + self.assertTrue('following_base' in [f.attname for f in m2m]) + related_m2m = Person._meta.get_all_related_many_to_many_objects() + self.assertTrue('followers_base' in [o.field.related_query_name() for o in related_m2m]) + + def test_related_m2m_symmetrical(self): + m2m = Person._meta.many_to_many + self.assertTrue('friends_base' in [f.attname for f in m2m]) + related_m2m = Person._meta.get_all_related_many_to_many_objects() + self.assertIn('friends_inherited_rel_+', [o.field.related_query_name() for o in related_m2m]) + + +@test.ignore_warnings(category=RemovedInDjango20Warning) +class GetFieldByNameTests(OptionsBaseTests): + + def test_get_data_field(self): + field_info = Person._meta.get_field_by_name('data_abstract') + self.assertEqual(field_info[1:], (BasePerson, True, False)) + self.assertIsInstance(field_info[0], CharField) + + def test_get_m2m_field(self): + field_info = Person._meta.get_field_by_name('m2m_base') + self.assertEqual(field_info[1:], (BasePerson, True, True)) + self.assertIsInstance(field_info[0], related.ManyToManyField) + + def test_get_related_object(self): + field_info = Person._meta.get_field_by_name('relating_baseperson') + self.assertEqual(field_info[1:], (BasePerson, False, False)) + self.assertTrue(field_info[0].auto_created) + + def test_get_related_m2m(self): + field_info = Person._meta.get_field_by_name('relating_people') + self.assertEqual(field_info[1:], (None, False, True)) + self.assertTrue(field_info[0].auto_created) + + def test_get_generic_relation(self): + field_info = Person._meta.get_field_by_name('generic_relation_base') + self.assertEqual(field_info[1:], (None, True, False)) + self.assertIsInstance(field_info[0], GenericRelation) + + def test_get_m2m_field_invalid(self): + with warnings.catch_warnings(record=True) as warning: + warnings.simplefilter("always") + self.assertRaises( + FieldDoesNotExist, + Person._meta.get_field, + **{'field_name': 'm2m_base', 'many_to_many': False} + ) + self.assertEqual(Person._meta.get_field('m2m_base', many_to_many=True).name, 'm2m_base') + + # 2 RemovedInDjango20Warning messages should be raised, one for each call of get_field() + # with the 'many_to_many' argument. + self.assertEqual( + [RemovedInDjango20Warning, RemovedInDjango20Warning], + [w.message.__class__ for w in warning] + ) + + +@test.ignore_warnings(category=RemovedInDjango20Warning) +class GetAllFieldNamesTestCase(OptionsBaseTests): + + def test_get_all_field_names(self): + for model, expected_names in TEST_RESULTS['get_all_field_names'].items(): + objects = model._meta.get_all_field_names() + self.assertEqual(sorted(map(str, objects)), sorted(expected_names)) diff --git a/tests/model_meta/tests.py b/tests/model_meta/tests.py new file mode 100644 index 0000000000..31ffa4ac93 --- /dev/null +++ b/tests/model_meta/tests.py @@ -0,0 +1,247 @@ +from django.apps import apps +from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation +from django.core.exceptions import FieldDoesNotExist +from django.db.models.fields import related, CharField, Field +from django.db.models.options import IMMUTABLE_WARNING, EMPTY_RELATION_TREE +from django.test import TestCase + +from .models import Relation, AbstractPerson, BasePerson, Person, ProxyPerson, Relating +from .results import TEST_RESULTS + + +class OptionsBaseTests(TestCase): + + def _map_related_query_names(self, res): + return tuple((o.name, m) for o, m in res) + + def _map_names(self, res): + return tuple((f.name, m) for f, m in res) + + def _model(self, current_model, field): + model = field.model._meta.concrete_model + return None if model == current_model else model + + def _details(self, current_model, relation): + direct = isinstance(relation, Field) or isinstance(relation, GenericForeignKey) + model = relation.model._meta.concrete_model + if model == current_model: + model = None + + field = relation if direct else relation.field + m2m = isinstance(field, related.ManyToManyField) + return relation, model, direct, m2m + + +class GetFieldsTests(OptionsBaseTests): + + def test_get_fields_is_immutable(self): + msg = IMMUTABLE_WARNING % "get_fields()" + for _ in range(2): + # Running unit test twice to ensure both non-cached and cached result + # are immutable. + fields = Person._meta.get_fields() + with self.assertRaisesMessage(AttributeError, msg): + fields += ["errors"] + + +class DataTests(OptionsBaseTests): + + def test_fields(self): + for model, expected_result in TEST_RESULTS['fields'].items(): + fields = model._meta.fields + self.assertEqual([f.attname for f in fields], expected_result) + + def test_local_fields(self): + is_data_field = lambda f: isinstance(f, Field) and not isinstance(f, related.ManyToManyField) + + for model, expected_result in TEST_RESULTS['local_fields'].items(): + fields = model._meta.local_fields + self.assertEqual([f.attname for f in fields], expected_result) + for f in fields: + self.assertEqual(f.model, model) + self.assertTrue(is_data_field(f)) + + def test_local_concrete_fields(self): + for model, expected_result in TEST_RESULTS['local_concrete_fields'].items(): + fields = model._meta.local_concrete_fields + self.assertEqual([f.attname for f in fields], expected_result) + for f in fields: + self.assertIsNotNone(f.column) + + +class M2MTests(OptionsBaseTests): + + def test_many_to_many(self): + for model, expected_result in TEST_RESULTS['many_to_many'].items(): + fields = model._meta.many_to_many + self.assertEqual([f.attname for f in fields], expected_result) + for f in fields: + self.assertTrue(f.many_to_many and f.is_relation) + + def test_many_to_many_with_model(self): + for model, expected_result in TEST_RESULTS['many_to_many_with_model'].items(): + models = [self._model(model, field) for field in model._meta.many_to_many] + self.assertEqual(models, expected_result) + + +class RelatedObjectsTests(OptionsBaseTests): + key_name = lambda self, r: r[0] + + def test_related_objects(self): + result_key = 'get_all_related_objects_with_model' + for model, expected in TEST_RESULTS[result_key].items(): + objects = [ + (field, self._model(model, field)) + for field in model._meta.get_fields() + if field.auto_created and not field.concrete + ] + self.assertEqual(self._map_related_query_names(objects), expected) + + def test_related_objects_local(self): + result_key = 'get_all_related_objects_with_model_local' + for model, expected in TEST_RESULTS[result_key].items(): + objects = [ + (field, self._model(model, field)) + for field in model._meta.get_fields(include_parents=False) + if field.auto_created and not field.concrete + ] + self.assertEqual(self._map_related_query_names(objects), expected) + + def test_related_objects_include_hidden(self): + result_key = 'get_all_related_objects_with_model_hidden' + for model, expected in TEST_RESULTS[result_key].items(): + objects = [ + (field, self._model(model, field)) + for field in model._meta.get_fields(include_hidden=True) + if field.auto_created and not field.concrete + ] + self.assertEqual( + sorted(self._map_names(objects), key=self.key_name), + sorted(expected, key=self.key_name) + ) + + def test_related_objects_include_hidden_local_only(self): + result_key = 'get_all_related_objects_with_model_hidden_local' + for model, expected in TEST_RESULTS[result_key].items(): + objects = [ + (field, self._model(model, field)) + for field in model._meta.get_fields(include_hidden=True, include_parents=False) + if field.auto_created and not field.concrete + ] + self.assertEqual( + sorted(self._map_names(objects), key=self.key_name), + sorted(expected, key=self.key_name) + ) + + +class VirtualFieldsTests(OptionsBaseTests): + + def test_virtual_fields(self): + for model, expected_names in TEST_RESULTS['virtual_fields'].items(): + objects = model._meta.virtual_fields + self.assertEqual(sorted([f.name for f in objects]), sorted(expected_names)) + + +class GetFieldByNameTests(OptionsBaseTests): + + def test_get_data_field(self): + field_info = self._details(Person, Person._meta.get_field('data_abstract')) + self.assertEqual(field_info[1:], (BasePerson, True, False)) + self.assertIsInstance(field_info[0], CharField) + + def test_get_m2m_field(self): + field_info = self._details(Person, Person._meta.get_field('m2m_base')) + self.assertEqual(field_info[1:], (BasePerson, True, True)) + self.assertIsInstance(field_info[0], related.ManyToManyField) + + def test_get_related_object(self): + field_info = self._details(Person, Person._meta.get_field('relating_baseperson')) + self.assertEqual(field_info[1:], (BasePerson, False, False)) + self.assertIsInstance(field_info[0], related.ForeignObjectRel) + + def test_get_related_m2m(self): + field_info = self._details(Person, Person._meta.get_field('relating_people')) + self.assertEqual(field_info[1:], (None, False, True)) + self.assertIsInstance(field_info[0], related.ForeignObjectRel) + + def test_get_generic_relation(self): + field_info = self._details(Person, Person._meta.get_field('generic_relation_base')) + self.assertEqual(field_info[1:], (None, True, False)) + self.assertIsInstance(field_info[0], GenericRelation) + + def test_get_fields_only_searaches_forward_on_apps_not_ready(self): + opts = Person._meta + # If apps registry is not ready, get_field() searches over only + # forward fields. + opts.apps.ready = False + try: + # 'data_abstract' is a forward field, and therefore will be found + self.assertTrue(opts.get_field('data_abstract')) + msg = ( + "Person has no field named 'relating_baseperson'. The app " + "cache isn't ready yet, so if this is a forward field, it " + "won't be available yet." + ) + # 'data_abstract' is a reverse field, and will raise an exception + with self.assertRaisesMessage(FieldDoesNotExist, msg): + opts.get_field('relating_baseperson') + finally: + opts.apps.ready = True + + +class RelationTreeTests(TestCase): + all_models = (Relation, AbstractPerson, BasePerson, Person, ProxyPerson, Relating) + + def setUp(self): + apps.clear_cache() + + def test_clear_cache_clears_relation_tree(self): + # The apps.clear_cache is setUp() should have deleted all trees. + # Exclude abstract models that are not included in the Apps registry + # and have no cache. + all_models_with_cache = (m for m in self.all_models if not m._meta.abstract) + for m in all_models_with_cache: + self.assertNotIn('_relation_tree', m._meta.__dict__) + + def test_first_relation_tree_access_populates_all(self): + # On first access, relation tree should have populated cache. + self.assertTrue(self.all_models[0]._meta._relation_tree) + + # AbstractPerson does not have any relations, so relation_tree + # should just return an EMPTY_RELATION_TREE. + self.assertEqual(AbstractPerson._meta._relation_tree, EMPTY_RELATION_TREE) + + # All the other models should already have their relation tree + # in the internal __dict__ . + all_models_but_abstractperson = (m for m in self.all_models if m is not AbstractPerson) + for m in all_models_but_abstractperson: + self.assertIn('_relation_tree', m._meta.__dict__) + + def test_relations_related_objects(self): + # Testing non hidden related objects + self.assertEqual( + sorted([field.related_query_name() for field in Relation._meta._relation_tree + if not field.rel.field.rel.is_hidden()]), + sorted([ + 'fk_abstract_rel', 'fk_abstract_rel', 'fk_abstract_rel', 'fk_base_rel', 'fk_base_rel', + 'fk_base_rel', 'fk_concrete_rel', 'fk_concrete_rel', 'fo_abstract_rel', 'fo_abstract_rel', + 'fo_abstract_rel', 'fo_base_rel', 'fo_base_rel', 'fo_base_rel', 'fo_concrete_rel', + 'fo_concrete_rel', 'm2m_abstract_rel', 'm2m_abstract_rel', 'm2m_abstract_rel', + 'm2m_base_rel', 'm2m_base_rel', 'm2m_base_rel', 'm2m_concrete_rel', 'm2m_concrete_rel', + ]) + ) + # Testing hidden related objects + self.assertEqual( + sorted([field.related_query_name() for field in BasePerson._meta._relation_tree]), + sorted([ + '+', '+', 'BasePerson_following_abstract+', 'BasePerson_following_abstract+', + 'BasePerson_following_base+', 'BasePerson_following_base+', 'BasePerson_friends_abstract+', + 'BasePerson_friends_abstract+', 'BasePerson_friends_base+', 'BasePerson_friends_base+', + 'BasePerson_m2m_abstract+', 'BasePerson_m2m_base+', 'Relating_basepeople+', + 'Relating_basepeople_hidden+', 'followers_abstract', 'followers_abstract', 'followers_abstract', + 'followers_base', 'followers_base', 'followers_base', 'friends_abstract_rel_+', 'friends_abstract_rel_+', + 'friends_abstract_rel_+', 'friends_base_rel_+', 'friends_base_rel_+', 'friends_base_rel_+', 'person', + 'person', 'relating_basepeople', 'relating_baseperson', + ]) + ) + self.assertEqual([field.related_query_name() for field in AbstractPerson._meta._relation_tree], []) diff --git a/tests/queries/tests.py b/tests/queries/tests.py index aed122a7c1..900149b873 100644 --- a/tests/queries/tests.py +++ b/tests/queries/tests.py @@ -2093,7 +2093,7 @@ class CloneTests(TestCase): testing is impossible, this is a sanity check against invalid use of deepcopy. refs #16759. """ - opts_class = type(Note._meta.get_field_by_name("misc")[0]) + opts_class = type(Note._meta.get_field("misc")) note_deepcopy = getattr(opts_class, "__deepcopy__", None) opts_class.__deepcopy__ = lambda obj, memo: self.fail("Model fields shouldn't be cloned") try: diff --git a/tests/queryset_pickle/tests.py b/tests/queryset_pickle/tests.py index 22b61199f4..91fe304f9d 100644 --- a/tests/queryset_pickle/tests.py +++ b/tests/queryset_pickle/tests.py @@ -79,7 +79,7 @@ class PickleabilityTestCase(TestCase): m1 = M2MModel.objects.create() g1 = Group.objects.create(name='foof') m1.groups.add(g1) - m2m_through = M2MModel._meta.get_field_by_name('groups')[0].rel.through + m2m_through = M2MModel._meta.get_field('groups').rel.through original = m2m_through.objects.get() dumped = pickle.dumps(original) reloaded = pickle.loads(dumped) diff --git a/tests/schema/tests.py b/tests/schema/tests.py index e9de2131a9..b10ad07251 100644 --- a/tests/schema/tests.py +++ b/tests/schema/tests.py @@ -138,7 +138,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Book, - Book._meta.get_field_by_name("author")[0], + Book._meta.get_field("author"), new_field, strict=True, ) @@ -393,7 +393,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Author, - Author._meta.get_field_by_name("name")[0], + Author._meta.get_field("name"), new_field, strict=True, ) @@ -424,7 +424,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Note, - Note._meta.get_field_by_name("info")[0], + Note._meta.get_field("info"), new_field, strict=True, ) @@ -451,7 +451,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Author, - Author._meta.get_field_by_name("height")[0], + Author._meta.get_field("height"), new_field ) # Ensure the field is right afterwards @@ -479,7 +479,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( AuthorWithDefaultHeight, - AuthorWithDefaultHeight._meta.get_field_by_name("height")[0], + AuthorWithDefaultHeight._meta.get_field("height"), new_field, ) # Ensure the field is right afterwards @@ -512,7 +512,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Book, - Book._meta.get_field_by_name("author")[0], + Book._meta.get_field("author"), new_field, strict=True, ) @@ -542,7 +542,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Author, - Author._meta.get_field_by_name("id")[0], + Author._meta.get_field("id"), new_field, strict=True, ) @@ -568,7 +568,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Author, - Author._meta.get_field_by_name("name")[0], + Author._meta.get_field("name"), new_field, strict=True, ) @@ -587,7 +587,7 @@ class SchemaTests(TransactionTestCase): editor.create_model(TagM2MTest) editor.create_model(BookWithM2M) # Ensure there is now an m2m table there - columns = self.column_classes(BookWithM2M._meta.get_field_by_name("tags")[0].rel.through) + columns = self.column_classes(BookWithM2M._meta.get_field("tags").rel.through) self.assertEqual(columns['tagm2mtest_id'][0], "IntegerField") def test_m2m_create_through(self): @@ -661,7 +661,7 @@ class SchemaTests(TransactionTestCase): self.assertEqual(len(self.column_classes(AuthorTag)), 3) # "Alter" the field's blankness. This should not actually do anything. with connection.schema_editor() as editor: - old_field = AuthorWithM2MThrough._meta.get_field_by_name("tags")[0] + old_field = AuthorWithM2MThrough._meta.get_field("tags") new_field = ManyToManyField("schema.TagM2MTest", related_name="authors", through="AuthorTag") new_field.contribute_to_class(AuthorWithM2MThrough, "tags") editor.alter_field( @@ -683,7 +683,7 @@ class SchemaTests(TransactionTestCase): editor.create_model(TagM2MTest) editor.create_model(UniqueTest) # Ensure the M2M exists and points to TagM2MTest - constraints = self.get_constraints(BookWithM2M._meta.get_field_by_name("tags")[0].rel.through._meta.db_table) + constraints = self.get_constraints(BookWithM2M._meta.get_field("tags").rel.through._meta.db_table) if connection.features.supports_foreign_keys: for name, details in constraints.items(): if details['columns'] == ["tagm2mtest_id"] and details['foreign_key']: @@ -698,11 +698,11 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Author, - BookWithM2M._meta.get_field_by_name("tags")[0], + BookWithM2M._meta.get_field("tags"), new_field, ) # Ensure old M2M is gone - self.assertRaises(DatabaseError, self.column_classes, BookWithM2M._meta.get_field_by_name("tags")[0].rel.through) + self.assertRaises(DatabaseError, self.column_classes, BookWithM2M._meta.get_field("tags").rel.through) # Ensure the new M2M exists and points to UniqueTest constraints = self.get_constraints(new_field.rel.through._meta.db_table) if connection.features.supports_foreign_keys: @@ -715,10 +715,10 @@ class SchemaTests(TransactionTestCase): finally: # Cleanup through table separately with connection.schema_editor() as editor: - editor.remove_field(BookWithM2M, BookWithM2M._meta.get_field_by_name("uniques")[0]) + editor.remove_field(BookWithM2M, BookWithM2M._meta.get_field("uniques")) # Cleanup model states BookWithM2M._meta.local_many_to_many.remove(new_field) - del BookWithM2M._meta._m2m_cache + BookWithM2M._meta._expire_cache() @unittest.skipUnless(connection.features.supports_column_check_constraints, "No check constraints") def test_check_constraints(self): @@ -741,7 +741,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Author, - Author._meta.get_field_by_name("height")[0], + Author._meta.get_field("height"), new_field, strict=True, ) @@ -754,7 +754,7 @@ class SchemaTests(TransactionTestCase): editor.alter_field( Author, new_field, - Author._meta.get_field_by_name("height")[0], + Author._meta.get_field("height"), strict=True, ) constraints = self.get_constraints(Author._meta.db_table) @@ -781,7 +781,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Tag, - Tag._meta.get_field_by_name("slug")[0], + Tag._meta.get_field("slug"), new_field, strict=True, ) @@ -809,8 +809,8 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Tag, - Tag._meta.get_field_by_name("slug")[0], - TagUniqueRename._meta.get_field_by_name("slug2")[0], + Tag._meta.get_field("slug"), + TagUniqueRename._meta.get_field("slug2"), strict=True, ) # Ensure the field is still unique @@ -976,7 +976,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( Book, - Book._meta.get_field_by_name("title")[0], + Book._meta.get_field("title"), new_field, strict=True, ) @@ -990,7 +990,7 @@ class SchemaTests(TransactionTestCase): editor.alter_field( Book, new_field, - Book._meta.get_field_by_name("title")[0], + Book._meta.get_field("title"), strict=True, ) # Ensure the table is there and has the index again @@ -1002,7 +1002,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.add_field( Book, - BookWithSlug._meta.get_field_by_name("slug")[0], + BookWithSlug._meta.get_field("slug"), ) self.assertIn( "slug", @@ -1014,7 +1014,7 @@ class SchemaTests(TransactionTestCase): with connection.schema_editor() as editor: editor.alter_field( BookWithSlug, - BookWithSlug._meta.get_field_by_name("slug")[0], + BookWithSlug._meta.get_field("slug"), new_field2, strict=True, ) @@ -1039,10 +1039,10 @@ class SchemaTests(TransactionTestCase): new_field.set_attributes_from_name("slug") new_field.model = Tag with connection.schema_editor() as editor: - editor.remove_field(Tag, Tag._meta.get_field_by_name("id")[0]) + editor.remove_field(Tag, Tag._meta.get_field("id")) editor.alter_field( Tag, - Tag._meta.get_field_by_name("slug")[0], + Tag._meta.get_field("slug"), new_field, ) # Ensure the PK changed |
