django/tests/model_fields/test_field_flags.py

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

222 lines
7.1 KiB
Python
Raw Normal View History

from django import test
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.db import models
from .models import AllFieldsModel
NON_CONCRETE_FIELDS = (
models.ForeignObject,
GenericForeignKey,
GenericRelation,
)
NON_EDITABLE_FIELDS = (
models.BinaryField,
GenericForeignKey,
GenericRelation,
)
RELATION_FIELDS = (
models.ForeignKey,
models.ForeignObject,
models.ManyToManyField,
models.OneToOneField,
GenericForeignKey,
GenericRelation,
)
MANY_TO_MANY_CLASSES = {
models.ManyToManyField,
}
MANY_TO_ONE_CLASSES = {
models.ForeignObject,
models.ForeignKey,
GenericForeignKey,
}
ONE_TO_MANY_CLASSES = {
models.ForeignObjectRel,
models.ManyToOneRel,
GenericRelation,
}
ONE_TO_ONE_CLASSES = {
models.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.SimpleTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.fields = [
*AllFieldsModel._meta.fields,
*AllFieldsModel._meta.private_fields,
]
cls.all_fields = [
*cls.fields,
*AllFieldsModel._meta.many_to_many,
*AllFieldsModel._meta.private_fields,
]
cls.fields_and_reverse_objects = [
*cls.all_fields,
*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(
2016-04-08 10:04:45 +08:00
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.remote_field
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.remote_field
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.remote_field
self.assertEqual(field.model, reverse_field.related_model)
self.assertEqual(field.related_model, reverse_field.model)
def test_null(self):
# null isn't well defined for a ManyToManyField, but changing it to
# True causes backwards compatibility problems (#25320).
self.assertFalse(AllFieldsModel._meta.get_field("m2m").null)
self.assertTrue(AllFieldsModel._meta.get_field("reverse2").null)