summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDaniel Pyrathon <pirosb3@gmail.com>2015-01-06 19:16:35 -0500
committerTim Graham <timograham@gmail.com>2015-01-06 19:25:12 -0500
commitfb48eb05816b1ac87d58696cdfe48be18c901f16 (patch)
tree3d2e981b6f3fafdeb7310d0734fb148ebb7f6aef /tests
parent749d23251bbd6564341405e6f8c1da129b8307e7 (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.py2
-rw-r--r--tests/basic/tests.py2
-rw-r--r--tests/fixtures/tests.py2
-rw-r--r--tests/generic_relations/tests.py3
-rw-r--r--tests/generic_relations_regress/tests.py2
-rw-r--r--tests/m2m_and_m2o/tests.py6
-rw-r--r--tests/many_to_one/tests.py4
-rw-r--r--tests/migrations/test_state.py4
-rw-r--r--tests/model_fields/models.py51
-rw-r--r--tests/model_fields/test_field_flags.py220
-rw-r--r--tests/model_fields/tests.py2
-rw-r--r--tests/model_meta/results.py796
-rw-r--r--tests/model_meta/test.py661
-rw-r--r--tests/model_meta/test_legacy.py166
-rw-r--r--tests/model_meta/tests.py247
-rw-r--r--tests/queries/tests.py2
-rw-r--r--tests/queryset_pickle/tests.py2
-rw-r--r--tests/schema/tests.py52
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