summaryrefslogtreecommitdiff
path: root/tests/invalid_models_tests
diff options
context:
space:
mode:
authordjango-bot <ops@djangoproject.com>2022-02-03 20:24:19 +0100
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2022-02-07 20:37:05 +0100
commit9c19aff7c7561e3a82978a272ecdaad40dda5c00 (patch)
treef0506b668a013d0063e5fba3dbf4863b466713ba /tests/invalid_models_tests
parentf68fa8b45dfac545cfc4111d4e52804c86db68d3 (diff)
downloaddjango-9c19aff7c7561e3a82978a272ecdaad40dda5c00.tar.gz
Refs #33476 -- Reformatted code with Black.
Diffstat (limited to 'tests/invalid_models_tests')
-rw-r--r--tests/invalid_models_tests/test_backend_specific.py19
-rw-r--r--tests/invalid_models_tests/test_custom_fields.py5
-rw-r--r--tests/invalid_models_tests/test_deprecated_fields.py78
-rw-r--r--tests/invalid_models_tests/test_models.py2446
-rw-r--r--tests/invalid_models_tests/test_ordinary_fields.py1085
-rw-r--r--tests/invalid_models_tests/test_relative_fields.py2156
6 files changed, 3244 insertions, 2545 deletions
diff --git a/tests/invalid_models_tests/test_backend_specific.py b/tests/invalid_models_tests/test_backend_specific.py
index 236909d50e..8461641c9a 100644
--- a/tests/invalid_models_tests/test_backend_specific.py
+++ b/tests/invalid_models_tests/test_backend_specific.py
@@ -9,20 +9,21 @@ from django.test.utils import isolate_apps
def dummy_allow_migrate(db, app_label, **hints):
# Prevent checks from being run on the 'other' database, which doesn't have
# its check_field() method mocked in the test.
- return db == 'default'
+ return db == "default"
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class BackendSpecificChecksTests(SimpleTestCase):
-
- @mock.patch('django.db.models.fields.router.allow_migrate', new=dummy_allow_migrate)
+ @mock.patch("django.db.models.fields.router.allow_migrate", new=dummy_allow_migrate)
def test_check_field(self):
- """ Test if backend specific checks are performed. """
- error = Error('an error')
+ """Test if backend specific checks are performed."""
+ error = Error("an error")
class Model(models.Model):
field = models.IntegerField()
- field = Model._meta.get_field('field')
- with mock.patch.object(connections['default'].validation, 'check_field', return_value=[error]):
- self.assertEqual(field.check(databases={'default'}), [error])
+ field = Model._meta.get_field("field")
+ with mock.patch.object(
+ connections["default"].validation, "check_field", return_value=[error]
+ ):
+ self.assertEqual(field.check(databases={"default"}), [error])
diff --git a/tests/invalid_models_tests/test_custom_fields.py b/tests/invalid_models_tests/test_custom_fields.py
index af14bae569..cfca888bec 100644
--- a/tests/invalid_models_tests/test_custom_fields.py
+++ b/tests/invalid_models_tests/test_custom_fields.py
@@ -3,9 +3,8 @@ from django.test import SimpleTestCase
from django.test.utils import isolate_apps
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class CustomFieldTest(SimpleTestCase):
-
def test_none_column(self):
class NoColumnField(models.AutoField):
def db_type(self, connection):
@@ -16,5 +15,5 @@ class CustomFieldTest(SimpleTestCase):
field = NoColumnField(primary_key=True, db_column="other_field")
other_field = models.IntegerField()
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
self.assertEqual(field.check(), [])
diff --git a/tests/invalid_models_tests/test_deprecated_fields.py b/tests/invalid_models_tests/test_deprecated_fields.py
index a3ee618ce4..fee5fb39f8 100644
--- a/tests/invalid_models_tests/test_deprecated_fields.py
+++ b/tests/invalid_models_tests/test_deprecated_fields.py
@@ -6,7 +6,7 @@ from django.test import SimpleTestCase
from django.test.utils import isolate_apps
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class DeprecatedFieldsTests(SimpleTestCase):
def test_IPAddressField_deprecated(self):
class IPAddressModel(models.Model):
@@ -15,13 +15,15 @@ class DeprecatedFieldsTests(SimpleTestCase):
model = IPAddressModel()
self.assertEqual(
model.check(),
- [checks.Error(
- 'IPAddressField has been removed except for support in '
- 'historical migrations.',
- hint='Use GenericIPAddressField instead.',
- obj=IPAddressModel._meta.get_field('ip'),
- id='fields.E900',
- )],
+ [
+ checks.Error(
+ "IPAddressField has been removed except for support in "
+ "historical migrations.",
+ hint="Use GenericIPAddressField instead.",
+ obj=IPAddressModel._meta.get_field("ip"),
+ id="fields.E900",
+ )
+ ],
)
def test_CommaSeparatedIntegerField_deprecated(self):
@@ -31,13 +33,15 @@ class DeprecatedFieldsTests(SimpleTestCase):
model = CommaSeparatedIntegerModel()
self.assertEqual(
model.check(),
- [checks.Error(
- 'CommaSeparatedIntegerField is removed except for support in '
- 'historical migrations.',
- hint='Use CharField(validators=[validate_comma_separated_integer_list]) instead.',
- obj=CommaSeparatedIntegerModel._meta.get_field('csi'),
- id='fields.E901',
- )],
+ [
+ checks.Error(
+ "CommaSeparatedIntegerField is removed except for support in "
+ "historical migrations.",
+ hint="Use CharField(validators=[validate_comma_separated_integer_list]) instead.",
+ obj=CommaSeparatedIntegerModel._meta.get_field("csi"),
+ id="fields.E901",
+ )
+ ],
)
def test_nullbooleanfield_deprecated(self):
@@ -45,29 +49,35 @@ class DeprecatedFieldsTests(SimpleTestCase):
nb = models.NullBooleanField()
model = NullBooleanFieldModel()
- self.assertEqual(model.check(), [
- checks.Error(
- 'NullBooleanField is removed except for support in historical '
- 'migrations.',
- hint='Use BooleanField(null=True) instead.',
- obj=NullBooleanFieldModel._meta.get_field('nb'),
- id='fields.E903',
- ),
- ])
+ self.assertEqual(
+ model.check(),
+ [
+ checks.Error(
+ "NullBooleanField is removed except for support in historical "
+ "migrations.",
+ hint="Use BooleanField(null=True) instead.",
+ obj=NullBooleanFieldModel._meta.get_field("nb"),
+ id="fields.E903",
+ ),
+ ],
+ )
- @skipUnless(connection.vendor == 'postgresql', 'PostgreSQL specific SQL')
+ @skipUnless(connection.vendor == "postgresql", "PostgreSQL specific SQL")
def test_postgres_jsonfield_deprecated(self):
from django.contrib.postgres.fields import JSONField
class PostgresJSONFieldModel(models.Model):
field = JSONField()
- self.assertEqual(PostgresJSONFieldModel.check(), [
- checks.Error(
- 'django.contrib.postgres.fields.JSONField is removed except '
- 'for support in historical migrations.',
- hint='Use django.db.models.JSONField instead.',
- obj=PostgresJSONFieldModel._meta.get_field('field'),
- id='fields.E904',
- ),
- ])
+ self.assertEqual(
+ PostgresJSONFieldModel.check(),
+ [
+ checks.Error(
+ "django.contrib.postgres.fields.JSONField is removed except "
+ "for support in historical migrations.",
+ hint="Use django.db.models.JSONField instead.",
+ obj=PostgresJSONFieldModel._meta.get_field("field"),
+ id="fields.E904",
+ ),
+ ],
+ )
diff --git a/tests/invalid_models_tests/test_models.py b/tests/invalid_models_tests/test_models.py
index c8c4cfa420..6daa14f0ad 100644
--- a/tests/invalid_models_tests/test_models.py
+++ b/tests/invalid_models_tests/test_models.py
@@ -17,7 +17,7 @@ def get_max_column_name_length():
allowed_len = None
db_alias = None
- for db in ('default', 'other'):
+ for db in ("default", "other"):
connection = connections[db]
max_name_length = connection.ops.max_name_length()
if max_name_length is not None and not connection.features.truncates_names:
@@ -28,60 +28,71 @@ def get_max_column_name_length():
return (allowed_len, db_alias)
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class IndexTogetherTests(SimpleTestCase):
-
def test_non_iterable(self):
class Model(models.Model):
class Meta:
index_together = 42
- self.assertEqual(Model.check(), [
- Error(
- "'index_together' must be a list or tuple.",
- obj=Model,
- id='models.E008',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'index_together' must be a list or tuple.",
+ obj=Model,
+ id="models.E008",
+ ),
+ ],
+ )
def test_non_list(self):
class Model(models.Model):
class Meta:
- index_together = 'not-a-list'
+ index_together = "not-a-list"
- self.assertEqual(Model.check(), [
- Error(
- "'index_together' must be a list or tuple.",
- obj=Model,
- id='models.E008',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'index_together' must be a list or tuple.",
+ obj=Model,
+ id="models.E008",
+ ),
+ ],
+ )
def test_list_containing_non_iterable(self):
class Model(models.Model):
class Meta:
- index_together = [('a', 'b'), 42]
+ index_together = [("a", "b"), 42]
- self.assertEqual(Model.check(), [
- Error(
- "All 'index_together' elements must be lists or tuples.",
- obj=Model,
- id='models.E009',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "All 'index_together' elements must be lists or tuples.",
+ obj=Model,
+ id="models.E009",
+ ),
+ ],
+ )
def test_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
- index_together = [['missing_field']]
+ index_together = [["missing_field"]]
- self.assertEqual(Model.check(), [
- Error(
- "'index_together' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'index_together' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
def test_pointing_to_non_local_field(self):
class Foo(models.Model):
@@ -91,64 +102,76 @@ class IndexTogetherTests(SimpleTestCase):
field2 = models.IntegerField()
class Meta:
- index_together = [['field2', 'field1']]
+ index_together = [["field2", "field1"]]
- self.assertEqual(Bar.check(), [
- Error(
- "'index_together' refers to field 'field1' which is not "
- "local to model 'Bar'.",
- hint='This issue may be caused by multi-table inheritance.',
- obj=Bar,
- id='models.E016',
- ),
- ])
+ self.assertEqual(
+ Bar.check(),
+ [
+ Error(
+ "'index_together' refers to field 'field1' which is not "
+ "local to model 'Bar'.",
+ hint="This issue may be caused by multi-table inheritance.",
+ obj=Bar,
+ id="models.E016",
+ ),
+ ],
+ )
def test_pointing_to_m2m_field(self):
class Model(models.Model):
- m2m = models.ManyToManyField('self')
+ m2m = models.ManyToManyField("self")
class Meta:
- index_together = [['m2m']]
+ index_together = [["m2m"]]
- self.assertEqual(Model.check(), [
- Error(
- "'index_together' refers to a ManyToManyField 'm2m', but "
- "ManyToManyFields are not permitted in 'index_together'.",
- obj=Model,
- id='models.E013',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'index_together' refers to a ManyToManyField 'm2m', but "
+ "ManyToManyFields are not permitted in 'index_together'.",
+ obj=Model,
+ id="models.E013",
+ ),
+ ],
+ )
def test_pointing_to_fk(self):
class Foo(models.Model):
pass
class Bar(models.Model):
- foo_1 = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name='bar_1')
- foo_2 = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name='bar_2')
+ foo_1 = models.ForeignKey(
+ Foo, on_delete=models.CASCADE, related_name="bar_1"
+ )
+ foo_2 = models.ForeignKey(
+ Foo, on_delete=models.CASCADE, related_name="bar_2"
+ )
class Meta:
- index_together = [['foo_1_id', 'foo_2']]
+ index_together = [["foo_1_id", "foo_2"]]
self.assertEqual(Bar.check(), [])
# unique_together tests are very similar to index_together tests.
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class UniqueTogetherTests(SimpleTestCase):
-
def test_non_iterable(self):
class Model(models.Model):
class Meta:
unique_together = 42
- self.assertEqual(Model.check(), [
- Error(
- "'unique_together' must be a list or tuple.",
- obj=Model,
- id='models.E010',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'unique_together' must be a list or tuple.",
+ obj=Model,
+ id="models.E010",
+ ),
+ ],
+ )
def test_list_containing_non_iterable(self):
class Model(models.Model):
@@ -156,28 +179,34 @@ class UniqueTogetherTests(SimpleTestCase):
two = models.IntegerField()
class Meta:
- unique_together = [('a', 'b'), 42]
+ unique_together = [("a", "b"), 42]
- self.assertEqual(Model.check(), [
- Error(
- "All 'unique_together' elements must be lists or tuples.",
- obj=Model,
- id='models.E011',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "All 'unique_together' elements must be lists or tuples.",
+ obj=Model,
+ id="models.E011",
+ ),
+ ],
+ )
def test_non_list(self):
class Model(models.Model):
class Meta:
- unique_together = 'not-a-list'
+ unique_together = "not-a-list"
- self.assertEqual(Model.check(), [
- Error(
- "'unique_together' must be a list or tuple.",
- obj=Model,
- id='models.E010',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'unique_together' must be a list or tuple.",
+ obj=Model,
+ id="models.E010",
+ ),
+ ],
+ )
def test_valid_model(self):
class Model(models.Model):
@@ -186,84 +215,99 @@ class UniqueTogetherTests(SimpleTestCase):
class Meta:
# unique_together can be a simple tuple
- unique_together = ('one', 'two')
+ unique_together = ("one", "two")
self.assertEqual(Model.check(), [])
def test_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
- unique_together = [['missing_field']]
+ unique_together = [["missing_field"]]
- self.assertEqual(Model.check(), [
- Error(
- "'unique_together' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'unique_together' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
def test_pointing_to_m2m(self):
class Model(models.Model):
- m2m = models.ManyToManyField('self')
+ m2m = models.ManyToManyField("self")
class Meta:
- unique_together = [['m2m']]
+ unique_together = [["m2m"]]
- self.assertEqual(Model.check(), [
- Error(
- "'unique_together' refers to a ManyToManyField 'm2m', but "
- "ManyToManyFields are not permitted in 'unique_together'.",
- obj=Model,
- id='models.E013',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'unique_together' refers to a ManyToManyField 'm2m', but "
+ "ManyToManyFields are not permitted in 'unique_together'.",
+ obj=Model,
+ id="models.E013",
+ ),
+ ],
+ )
def test_pointing_to_fk(self):
class Foo(models.Model):
pass
class Bar(models.Model):
- foo_1 = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name='bar_1')
- foo_2 = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name='bar_2')
+ foo_1 = models.ForeignKey(
+ Foo, on_delete=models.CASCADE, related_name="bar_1"
+ )
+ foo_2 = models.ForeignKey(
+ Foo, on_delete=models.CASCADE, related_name="bar_2"
+ )
class Meta:
- unique_together = [['foo_1_id', 'foo_2']]
+ unique_together = [["foo_1_id", "foo_2"]]
self.assertEqual(Bar.check(), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class IndexesTests(TestCase):
-
def test_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
- indexes = [models.Index(fields=['missing_field'], name='name')]
+ indexes = [models.Index(fields=["missing_field"], name="name")]
- self.assertEqual(Model.check(), [
- Error(
- "'indexes' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'indexes' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
def test_pointing_to_m2m_field(self):
class Model(models.Model):
- m2m = models.ManyToManyField('self')
+ m2m = models.ManyToManyField("self")
class Meta:
- indexes = [models.Index(fields=['m2m'], name='name')]
+ indexes = [models.Index(fields=["m2m"], name="name")]
- self.assertEqual(Model.check(), [
- Error(
- "'indexes' refers to a ManyToManyField 'm2m', but "
- "ManyToManyFields are not permitted in 'indexes'.",
- obj=Model,
- id='models.E013',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'indexes' refers to a ManyToManyField 'm2m', but "
+ "ManyToManyFields are not permitted in 'indexes'.",
+ obj=Model,
+ id="models.E013",
+ ),
+ ],
+ )
def test_pointing_to_non_local_field(self):
class Foo(models.Model):
@@ -273,28 +317,37 @@ class IndexesTests(TestCase):
field2 = models.IntegerField()
class Meta:
- indexes = [models.Index(fields=['field2', 'field1'], name='name')]
+ indexes = [models.Index(fields=["field2", "field1"], name="name")]
- self.assertEqual(Bar.check(), [
- Error(
- "'indexes' refers to field 'field1' which is not local to "
- "model 'Bar'.",
- hint='This issue may be caused by multi-table inheritance.',
- obj=Bar,
- id='models.E016',
- ),
- ])
+ self.assertEqual(
+ Bar.check(),
+ [
+ Error(
+ "'indexes' refers to field 'field1' which is not local to "
+ "model 'Bar'.",
+ hint="This issue may be caused by multi-table inheritance.",
+ obj=Bar,
+ id="models.E016",
+ ),
+ ],
+ )
def test_pointing_to_fk(self):
class Foo(models.Model):
pass
class Bar(models.Model):
- foo_1 = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name='bar_1')
- foo_2 = models.ForeignKey(Foo, on_delete=models.CASCADE, related_name='bar_2')
+ foo_1 = models.ForeignKey(
+ Foo, on_delete=models.CASCADE, related_name="bar_1"
+ )
+ foo_2 = models.ForeignKey(
+ Foo, on_delete=models.CASCADE, related_name="bar_2"
+ )
class Meta:
- indexes = [models.Index(fields=['foo_1_id', 'foo_2'], name='index_name')]
+ indexes = [
+ models.Index(fields=["foo_1_id", "foo_2"], name="index_name")
+ ]
self.assertEqual(Bar.check(), [])
@@ -302,34 +355,41 @@ class IndexesTests(TestCase):
class Model(models.Model):
class Meta:
indexes = [
- models.Index(fields=['id'], name='_index_name'),
- models.Index(fields=['id'], name='5index_name'),
+ models.Index(fields=["id"], name="_index_name"),
+ models.Index(fields=["id"], name="5index_name"),
]
- self.assertEqual(Model.check(), [
- Error(
- "The index name '%sindex_name' cannot start with an "
- "underscore or a number." % prefix,
- obj=Model,
- id='models.E033',
- ) for prefix in ('_', '5')
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "The index name '%sindex_name' cannot start with an "
+ "underscore or a number." % prefix,
+ obj=Model,
+ id="models.E033",
+ )
+ for prefix in ("_", "5")
+ ],
+ )
def test_max_name_length(self):
- index_name = 'x' * 31
+ index_name = "x" * 31
class Model(models.Model):
class Meta:
- indexes = [models.Index(fields=['id'], name=index_name)]
+ indexes = [models.Index(fields=["id"], name=index_name)]
- self.assertEqual(Model.check(), [
- Error(
- "The index name '%s' cannot be longer than 30 characters."
- % index_name,
- obj=Model,
- id='models.E034',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "The index name '%s' cannot be longer than 30 characters."
+ % index_name,
+ obj=Model,
+ id="models.E034",
+ ),
+ ],
+ )
def test_index_with_condition(self):
class Model(models.Model):
@@ -338,25 +398,29 @@ class IndexesTests(TestCase):
class Meta:
indexes = [
models.Index(
- fields=['age'],
- name='index_age_gte_10',
+ fields=["age"],
+ name="index_age_gte_10",
condition=models.Q(age__gte=10),
),
]
errors = Model.check(databases=self.databases)
- expected = [] if connection.features.supports_partial_indexes else [
- Warning(
- '%s does not support indexes with conditions.'
- % connection.display_name,
- hint=(
- "Conditions will be ignored. Silence this warning if you "
- "don't care about it."
- ),
- obj=Model,
- id='models.W037',
- )
- ]
+ expected = (
+ []
+ if connection.features.supports_partial_indexes
+ else [
+ Warning(
+ "%s does not support indexes with conditions."
+ % connection.display_name,
+ hint=(
+ "Conditions will be ignored. Silence this warning if you "
+ "don't care about it."
+ ),
+ obj=Model,
+ id="models.W037",
+ )
+ ]
+ )
self.assertEqual(errors, expected)
def test_index_with_condition_required_db_features(self):
@@ -364,11 +428,11 @@ class IndexesTests(TestCase):
age = models.IntegerField()
class Meta:
- required_db_features = {'supports_partial_indexes'}
+ required_db_features = {"supports_partial_indexes"}
indexes = [
models.Index(
- fields=['age'],
- name='index_age_gte_10',
+ fields=["age"],
+ name="index_age_gte_10",
condition=models.Q(age__gte=10),
),
]
@@ -382,25 +446,29 @@ class IndexesTests(TestCase):
class Meta:
indexes = [
models.Index(
- fields=['age'],
- name='index_age_include_id',
- include=['id'],
+ fields=["age"],
+ name="index_age_include_id",
+ include=["id"],
),
]
errors = Model.check(databases=self.databases)
- expected = [] if connection.features.supports_covering_indexes else [
- Warning(
- '%s does not support indexes with non-key columns.'
- % connection.display_name,
- hint=(
- "Non-key columns will be ignored. Silence this warning if "
- "you don't care about it."
- ),
- obj=Model,
- id='models.W040',
- )
- ]
+ expected = (
+ []
+ if connection.features.supports_covering_indexes
+ else [
+ Warning(
+ "%s does not support indexes with non-key columns."
+ % connection.display_name,
+ hint=(
+ "Non-key columns will be ignored. Silence this warning if "
+ "you don't care about it."
+ ),
+ obj=Model,
+ id="models.W040",
+ )
+ ]
+ )
self.assertEqual(errors, expected)
def test_index_with_include_required_db_features(self):
@@ -408,51 +476,57 @@ class IndexesTests(TestCase):
age = models.IntegerField()
class Meta:
- required_db_features = {'supports_covering_indexes'}
+ required_db_features = {"supports_covering_indexes"}
indexes = [
models.Index(
- fields=['age'],
- name='index_age_include_id',
- include=['id'],
+ fields=["age"],
+ name="index_age_include_id",
+ include=["id"],
),
]
self.assertEqual(Model.check(databases=self.databases), [])
- @skipUnlessDBFeature('supports_covering_indexes')
+ @skipUnlessDBFeature("supports_covering_indexes")
def test_index_include_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
indexes = [
- models.Index(fields=['id'], include=['missing_field'], name='name'),
+ models.Index(fields=["id"], include=["missing_field"], name="name"),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'indexes' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'indexes' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_covering_indexes')
+ @skipUnlessDBFeature("supports_covering_indexes")
def test_index_include_pointing_to_m2m_field(self):
class Model(models.Model):
- m2m = models.ManyToManyField('self')
+ m2m = models.ManyToManyField("self")
class Meta:
- indexes = [models.Index(fields=['id'], include=['m2m'], name='name')]
+ indexes = [models.Index(fields=["id"], include=["m2m"], name="name")]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'indexes' refers to a ManyToManyField 'm2m', but "
- "ManyToManyFields are not permitted in 'indexes'.",
- obj=Model,
- id='models.E013',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'indexes' refers to a ManyToManyField 'm2m', but "
+ "ManyToManyFields are not permitted in 'indexes'.",
+ obj=Model,
+ id="models.E013",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_covering_indexes')
+ @skipUnlessDBFeature("supports_covering_indexes")
def test_index_include_pointing_to_non_local_field(self):
class Parent(models.Model):
field1 = models.IntegerField()
@@ -462,34 +536,37 @@ class IndexesTests(TestCase):
class Meta:
indexes = [
- models.Index(fields=['field2'], include=['field1'], name='name'),
+ models.Index(fields=["field2"], include=["field1"], name="name"),
]
- self.assertEqual(Child.check(databases=self.databases), [
- Error(
- "'indexes' refers to field 'field1' which is not local to "
- "model 'Child'.",
- hint='This issue may be caused by multi-table inheritance.',
- obj=Child,
- id='models.E016',
- ),
- ])
+ self.assertEqual(
+ Child.check(databases=self.databases),
+ [
+ Error(
+ "'indexes' refers to field 'field1' which is not local to "
+ "model 'Child'.",
+ hint="This issue may be caused by multi-table inheritance.",
+ obj=Child,
+ id="models.E016",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_covering_indexes')
+ @skipUnlessDBFeature("supports_covering_indexes")
def test_index_include_pointing_to_fk(self):
class Target(models.Model):
pass
class Model(models.Model):
- fk_1 = models.ForeignKey(Target, models.CASCADE, related_name='target_1')
- fk_2 = models.ForeignKey(Target, models.CASCADE, related_name='target_2')
+ fk_1 = models.ForeignKey(Target, models.CASCADE, related_name="target_1")
+ fk_2 = models.ForeignKey(Target, models.CASCADE, related_name="target_2")
class Meta:
constraints = [
models.Index(
- fields=['id'],
- include=['fk_1_id', 'fk_2'],
- name='name',
+ fields=["id"],
+ include=["fk_1_id", "fk_2"],
+ name="name",
),
]
@@ -500,17 +577,16 @@ class IndexesTests(TestCase):
name = models.CharField(max_length=10)
class Meta:
- indexes = [models.Index(Lower('name'), name='index_lower_name')]
+ indexes = [models.Index(Lower("name"), name="index_lower_name")]
warn = Warning(
- '%s does not support indexes on expressions.'
- % connection.display_name,
+ "%s does not support indexes on expressions." % connection.display_name,
hint=(
"An index won't be created. Silence this warning if you don't "
"care about it."
),
obj=Model,
- id='models.W043',
+ id="models.W043",
)
expected = [] if connection.features.supports_expression_indexes else [warn]
self.assertEqual(Model.check(databases=self.databases), expected)
@@ -520,8 +596,8 @@ class IndexesTests(TestCase):
name = models.CharField(max_length=10)
class Meta:
- indexes = [models.Index(Lower('name'), name='index_lower_name')]
- required_db_features = {'supports_expression_indexes'}
+ indexes = [models.Index(Lower("name"), name="index_lower_name")]
+ required_db_features = {"supports_expression_indexes"}
self.assertEqual(Model.check(databases=self.databases), [])
@@ -533,8 +609,9 @@ class IndexesTests(TestCase):
class Meta:
indexes = [
models.Index(
- models.F('height') / (models.F('weight__abs') + models.Value(5)),
- name='name',
+ models.F("height")
+ / (models.F("weight__abs") + models.Value(5)),
+ name="name",
),
]
@@ -544,46 +621,55 @@ class IndexesTests(TestCase):
def test_func_index_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
- indexes = [models.Index(Lower('missing_field').desc(), name='name')]
+ indexes = [models.Index(Lower("missing_field").desc(), name="name")]
- self.assertEqual(Model.check(), [
- Error(
- "'indexes' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'indexes' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
def test_func_index_pointing_to_missing_field_nested(self):
class Model(models.Model):
class Meta:
indexes = [
- models.Index(Abs(Round('missing_field')), name='name'),
+ models.Index(Abs(Round("missing_field")), name="name"),
]
- self.assertEqual(Model.check(), [
- Error(
- "'indexes' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'indexes' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
def test_func_index_pointing_to_m2m_field(self):
class Model(models.Model):
- m2m = models.ManyToManyField('self')
+ m2m = models.ManyToManyField("self")
class Meta:
- indexes = [models.Index(Lower('m2m'), name='name')]
+ indexes = [models.Index(Lower("m2m"), name="name")]
- self.assertEqual(Model.check(), [
- Error(
- "'indexes' refers to a ManyToManyField 'm2m', but "
- "ManyToManyFields are not permitted in 'indexes'.",
- obj=Model,
- id='models.E013',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'indexes' refers to a ManyToManyField 'm2m', but "
+ "ManyToManyFields are not permitted in 'indexes'.",
+ obj=Model,
+ id="models.E013",
+ ),
+ ],
+ )
def test_func_index_pointing_to_non_local_field(self):
class Foo(models.Model):
@@ -591,87 +677,99 @@ class IndexesTests(TestCase):
class Bar(Foo):
class Meta:
- indexes = [models.Index(Lower('field1'), name='name')]
+ indexes = [models.Index(Lower("field1"), name="name")]
- self.assertEqual(Bar.check(), [
- Error(
- "'indexes' refers to field 'field1' which is not local to "
- "model 'Bar'.",
- hint='This issue may be caused by multi-table inheritance.',
- obj=Bar,
- id='models.E016',
- ),
- ])
+ self.assertEqual(
+ Bar.check(),
+ [
+ Error(
+ "'indexes' refers to field 'field1' which is not local to "
+ "model 'Bar'.",
+ hint="This issue may be caused by multi-table inheritance.",
+ obj=Bar,
+ id="models.E016",
+ ),
+ ],
+ )
def test_func_index_pointing_to_fk(self):
class Foo(models.Model):
pass
class Bar(models.Model):
- foo_1 = models.ForeignKey(Foo, models.CASCADE, related_name='bar_1')
- foo_2 = models.ForeignKey(Foo, models.CASCADE, related_name='bar_2')
+ foo_1 = models.ForeignKey(Foo, models.CASCADE, related_name="bar_1")
+ foo_2 = models.ForeignKey(Foo, models.CASCADE, related_name="bar_2")
class Meta:
indexes = [
- models.Index(Lower('foo_1_id'), Lower('foo_2'), name='index_name'),
+ models.Index(Lower("foo_1_id"), Lower("foo_2"), name="index_name"),
]
self.assertEqual(Bar.check(), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class FieldNamesTests(TestCase):
- databases = {'default', 'other'}
+ databases = {"default", "other"}
def test_ending_with_underscore(self):
class Model(models.Model):
field_ = models.CharField(max_length=10)
- m2m_ = models.ManyToManyField('self')
+ m2m_ = models.ManyToManyField("self")
- self.assertEqual(Model.check(), [
- Error(
- 'Field names must not end with an underscore.',
- obj=Model._meta.get_field('field_'),
- id='fields.E001',
- ),
- Error(
- 'Field names must not end with an underscore.',
- obj=Model._meta.get_field('m2m_'),
- id='fields.E001',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Field names must not end with an underscore.",
+ obj=Model._meta.get_field("field_"),
+ id="fields.E001",
+ ),
+ Error(
+ "Field names must not end with an underscore.",
+ obj=Model._meta.get_field("m2m_"),
+ id="fields.E001",
+ ),
+ ],
+ )
max_column_name_length, column_limit_db_alias = get_max_column_name_length()
- @unittest.skipIf(max_column_name_length is None, "The database doesn't have a column name length limit.")
+ @unittest.skipIf(
+ max_column_name_length is None,
+ "The database doesn't have a column name length limit.",
+ )
def test_M2M_long_column_name(self):
"""
#13711 -- Model check for long M2M column names when database has
column name length limits.
"""
# A model with very long name which will be used to set relations to.
- class VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz(models.Model):
+ class VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz(
+ models.Model
+ ):
title = models.CharField(max_length=11)
# Main model for which checks will be performed.
class ModelWithLongField(models.Model):
m2m_field = models.ManyToManyField(
VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,
- related_name='rn1',
+ related_name="rn1",
)
m2m_field2 = models.ManyToManyField(
VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,
- related_name='rn2', through='m2msimple',
+ related_name="rn2",
+ through="m2msimple",
)
m2m_field3 = models.ManyToManyField(
VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,
- related_name='rn3',
- through='m2mcomplex',
+ related_name="rn3",
+ through="m2mcomplex",
)
fk = models.ForeignKey(
VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,
models.CASCADE,
- related_name='rn4',
+ related_name="rn4",
)
# Models used for setting `through` in M2M field.
@@ -681,7 +779,7 @@ class FieldNamesTests(TestCase):
class m2mcomplex(models.Model):
id2 = models.ForeignKey(ModelWithLongField, models.CASCADE)
- long_field_name = 'a' * (self.max_column_name_length + 1)
+ long_field_name = "a" * (self.max_column_name_length + 1)
models.ForeignKey(
VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,
models.CASCADE,
@@ -690,13 +788,15 @@ class FieldNamesTests(TestCase):
models.ForeignKey(
VeryLongModelNamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz,
models.CASCADE,
- db_column=long_field_name
+ db_column=long_field_name,
).contribute_to_class(m2mcomplex, long_field_name)
- errors = ModelWithLongField.check(databases=('default', 'other'))
+ errors = ModelWithLongField.check(databases=("default", "other"))
# First error because of M2M field set on the model with long name.
- m2m_long_name = "verylongmodelnamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz_id"
+ m2m_long_name = (
+ "verylongmodelnamezzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz_id"
+ )
if self.max_column_name_length > len(m2m_long_name):
# Some databases support names longer than the test name.
expected = []
@@ -705,11 +805,15 @@ class FieldNamesTests(TestCase):
Error(
'Autogenerated column name too long for M2M field "%s". '
'Maximum length is "%s" for database "%s".'
- % (m2m_long_name, self.max_column_name_length, self.column_limit_db_alias),
+ % (
+ m2m_long_name,
+ self.max_column_name_length,
+ self.column_limit_db_alias,
+ ),
hint="Use 'through' to create a separate model for "
- "M2M and then set column_name using 'db_column'.",
+ "M2M and then set column_name using 'db_column'.",
obj=ModelWithLongField,
- id='models.E019',
+ id="models.E019",
)
]
@@ -722,11 +826,15 @@ class FieldNamesTests(TestCase):
Error(
'Autogenerated column name too long for M2M field "%s_id". '
'Maximum length is "%s" for database "%s".'
- % (long_field_name, self.max_column_name_length, self.column_limit_db_alias),
+ % (
+ long_field_name,
+ self.max_column_name_length,
+ self.column_limit_db_alias,
+ ),
hint="Use 'through' to create a separate model for "
- "M2M and then set column_name using 'db_column'.",
+ "M2M and then set column_name using 'db_column'.",
obj=ModelWithLongField,
- id='models.E019',
+ id="models.E019",
)
)
@@ -735,29 +843,44 @@ class FieldNamesTests(TestCase):
# aliases.
self.assertEqual(ModelWithLongField.check(databases=None), [])
- @unittest.skipIf(max_column_name_length is None, "The database doesn't have a column name length limit.")
+ @unittest.skipIf(
+ max_column_name_length is None,
+ "The database doesn't have a column name length limit.",
+ )
def test_local_field_long_column_name(self):
"""
#13711 -- Model check for long column names
when database does not support long names.
"""
+
class ModelWithLongField(models.Model):
title = models.CharField(max_length=11)
- long_field_name = 'a' * (self.max_column_name_length + 1)
- long_field_name2 = 'b' * (self.max_column_name_length + 1)
- models.CharField(max_length=11).contribute_to_class(ModelWithLongField, long_field_name)
- models.CharField(max_length=11, db_column='vlmn').contribute_to_class(ModelWithLongField, long_field_name2)
- self.assertEqual(ModelWithLongField.check(databases=('default', 'other')), [
- Error(
- 'Autogenerated column name too long for field "%s". '
- 'Maximum length is "%s" for database "%s".'
- % (long_field_name, self.max_column_name_length, self.column_limit_db_alias),
- hint="Set the column name manually using 'db_column'.",
- obj=ModelWithLongField,
- id='models.E018',
- )
- ])
+ long_field_name = "a" * (self.max_column_name_length + 1)
+ long_field_name2 = "b" * (self.max_column_name_length + 1)
+ models.CharField(max_length=11).contribute_to_class(
+ ModelWithLongField, long_field_name
+ )
+ models.CharField(max_length=11, db_column="vlmn").contribute_to_class(
+ ModelWithLongField, long_field_name2
+ )
+ self.assertEqual(
+ ModelWithLongField.check(databases=("default", "other")),
+ [
+ Error(
+ 'Autogenerated column name too long for field "%s". '
+ 'Maximum length is "%s" for database "%s".'
+ % (
+ long_field_name,
+ self.max_column_name_length,
+ self.column_limit_db_alias,
+ ),
+ hint="Set the column name manually using 'db_column'.",
+ obj=ModelWithLongField,
+ id="models.E018",
+ )
+ ],
+ )
# Check for long column names is called only for specified database
# aliases.
self.assertEqual(ModelWithLongField.check(databases=None), [])
@@ -766,45 +889,53 @@ class FieldNamesTests(TestCase):
class Model(models.Model):
some__field = models.IntegerField()
- self.assertEqual(Model.check(), [
- Error(
- 'Field names must not contain "__".',
- obj=Model._meta.get_field('some__field'),
- id='fields.E002',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ 'Field names must not contain "__".',
+ obj=Model._meta.get_field("some__field"),
+ id="fields.E002",
+ )
+ ],
+ )
def test_pk(self):
class Model(models.Model):
pk = models.IntegerField()
- self.assertEqual(Model.check(), [
- Error(
- "'pk' is a reserved word that cannot be used as a field name.",
- obj=Model._meta.get_field('pk'),
- id='fields.E003',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'pk' is a reserved word that cannot be used as a field name.",
+ obj=Model._meta.get_field("pk"),
+ id="fields.E003",
+ )
+ ],
+ )
def test_db_column_clash(self):
class Model(models.Model):
foo = models.IntegerField()
- bar = models.IntegerField(db_column='foo')
+ bar = models.IntegerField(db_column="foo")
- self.assertEqual(Model.check(), [
- Error(
- "Field 'bar' has column name 'foo' that is used by "
- "another field.",
- hint="Specify a 'db_column' for the field.",
- obj=Model,
- id='models.E007',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Field 'bar' has column name 'foo' that is used by "
+ "another field.",
+ hint="Specify a 'db_column' for the field.",
+ obj=Model,
+ id="models.E007",
+ )
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class ShadowingFieldsTests(SimpleTestCase):
-
def test_field_name_clash_with_child_accessor(self):
class Parent(models.Model):
pass
@@ -812,41 +943,47 @@ class ShadowingFieldsTests(SimpleTestCase):
class Child(Parent):
child = models.CharField(max_length=100)
- self.assertEqual(Child.check(), [
- Error(
- "The field 'child' clashes with the field "
- "'child' from model 'invalid_models_tests.parent'.",
- obj=Child._meta.get_field('child'),
- id='models.E006',
- )
- ])
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "The field 'child' clashes with the field "
+ "'child' from model 'invalid_models_tests.parent'.",
+ obj=Child._meta.get_field("child"),
+ id="models.E006",
+ )
+ ],
+ )
def test_field_name_clash_with_m2m_through(self):
class Parent(models.Model):
clash_id = models.IntegerField()
class Child(Parent):
- clash = models.ForeignKey('Child', models.CASCADE)
+ clash = models.ForeignKey("Child", models.CASCADE)
class Model(models.Model):
parents = models.ManyToManyField(
to=Parent,
- through='Through',
- through_fields=['parent', 'model'],
+ through="Through",
+ through_fields=["parent", "model"],
)
class Through(models.Model):
parent = models.ForeignKey(Parent, models.CASCADE)
model = models.ForeignKey(Model, models.CASCADE)
- self.assertEqual(Child.check(), [
- Error(
- "The field 'clash' clashes with the field 'clash_id' from "
- "model 'invalid_models_tests.parent'.",
- obj=Child._meta.get_field('clash'),
- id='models.E006',
- )
- ])
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "The field 'clash' clashes with the field 'clash_id' from "
+ "model 'invalid_models_tests.parent'.",
+ obj=Child._meta.get_field("clash"),
+ id="models.E006",
+ )
+ ],
+ )
def test_multiinheritance_clash(self):
class Mother(models.Model):
@@ -860,22 +997,25 @@ class ShadowingFieldsTests(SimpleTestCase):
# both parents define these fields.
pass
- self.assertEqual(Child.check(), [
- Error(
- "The field 'id' from parent model "
- "'invalid_models_tests.mother' clashes with the field 'id' "
- "from parent model 'invalid_models_tests.father'.",
- obj=Child,
- id='models.E005',
- ),
- Error(
- "The field 'clash' from parent model "
- "'invalid_models_tests.mother' clashes with the field 'clash' "
- "from parent model 'invalid_models_tests.father'.",
- obj=Child,
- id='models.E005',
- )
- ])
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "The field 'id' from parent model "
+ "'invalid_models_tests.mother' clashes with the field 'id' "
+ "from parent model 'invalid_models_tests.father'.",
+ obj=Child,
+ id="models.E005",
+ ),
+ Error(
+ "The field 'clash' from parent model "
+ "'invalid_models_tests.mother' clashes with the field 'clash' "
+ "from parent model 'invalid_models_tests.father'.",
+ obj=Child,
+ id="models.E005",
+ ),
+ ],
+ )
def test_inheritance_clash(self):
class Parent(models.Model):
@@ -889,14 +1029,17 @@ class ShadowingFieldsTests(SimpleTestCase):
# This field clashes with parent "f_id" field.
f = models.ForeignKey(Target, models.CASCADE)
- self.assertEqual(Child.check(), [
- Error(
- "The field 'f' clashes with the field 'f_id' "
- "from model 'invalid_models_tests.parent'.",
- obj=Child._meta.get_field('f'),
- id='models.E006',
- )
- ])
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "The field 'f' clashes with the field 'f_id' "
+ "from model 'invalid_models_tests.parent'.",
+ obj=Child._meta.get_field("f"),
+ id="models.E006",
+ )
+ ],
+ )
def test_multigeneration_inheritance(self):
class GrandParent(models.Model):
@@ -911,14 +1054,17 @@ class ShadowingFieldsTests(SimpleTestCase):
class GrandChild(Child):
clash = models.IntegerField()
- self.assertEqual(GrandChild.check(), [
- Error(
- "The field 'clash' clashes with the field 'clash' "
- "from model 'invalid_models_tests.grandparent'.",
- obj=GrandChild._meta.get_field('clash'),
- id='models.E006',
- )
- ])
+ self.assertEqual(
+ GrandChild.check(),
+ [
+ Error(
+ "The field 'clash' clashes with the field 'clash' "
+ "from model 'invalid_models_tests.grandparent'.",
+ obj=GrandChild._meta.get_field("clash"),
+ id="models.E006",
+ )
+ ],
+ )
def test_id_clash(self):
class Target(models.Model):
@@ -928,54 +1074,62 @@ class ShadowingFieldsTests(SimpleTestCase):
fk = models.ForeignKey(Target, models.CASCADE)
fk_id = models.IntegerField()
- self.assertEqual(Model.check(), [
- Error(
- "The field 'fk_id' clashes with the field 'fk' from model "
- "'invalid_models_tests.model'.",
- obj=Model._meta.get_field('fk_id'),
- id='models.E006',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "The field 'fk_id' clashes with the field 'fk' from model "
+ "'invalid_models_tests.model'.",
+ obj=Model._meta.get_field("fk_id"),
+ id="models.E006",
+ )
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class OtherModelTests(SimpleTestCase):
-
def test_unique_primary_key(self):
invalid_id = models.IntegerField(primary_key=False)
class Model(models.Model):
id = invalid_id
- self.assertEqual(Model.check(), [
- Error(
- "'id' can only be used as a field name if the field also sets "
- "'primary_key=True'.",
- obj=Model,
- id='models.E004',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'id' can only be used as a field name if the field also sets "
+ "'primary_key=True'.",
+ obj=Model,
+ id="models.E004",
+ ),
+ ],
+ )
def test_ordering_non_iterable(self):
class Model(models.Model):
class Meta:
- ordering = 'missing_field'
+ ordering = "missing_field"
- self.assertEqual(Model.check(), [
- Error(
- "'ordering' must be a tuple or list "
- "(even if you want to order by only one field).",
- obj=Model,
- id='models.E014',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'ordering' must be a tuple or list "
+ "(even if you want to order by only one field).",
+ obj=Model,
+ id="models.E014",
+ ),
+ ],
+ )
def test_just_ordering_no_errors(self):
class Model(models.Model):
order = models.PositiveIntegerField()
class Meta:
- ordering = ['order']
+ ordering = ["order"]
self.assertEqual(Model.check(), [])
@@ -987,7 +1141,7 @@ class OtherModelTests(SimpleTestCase):
question = models.ForeignKey(Question, models.CASCADE)
class Meta:
- order_with_respect_to = 'question'
+ order_with_respect_to = "question"
self.assertEqual(Answer.check(), [])
@@ -1000,16 +1154,19 @@ class OtherModelTests(SimpleTestCase):
order = models.IntegerField()
class Meta:
- order_with_respect_to = 'question'
- ordering = ['order']
+ order_with_respect_to = "question"
+ ordering = ["order"]
- self.assertEqual(Answer.check(), [
- Error(
- "'ordering' and 'order_with_respect_to' cannot be used together.",
- obj=Answer,
- id='models.E021',
- ),
- ])
+ self.assertEqual(
+ Answer.check(),
+ [
+ Error(
+ "'ordering' and 'order_with_respect_to' cannot be used together.",
+ obj=Answer,
+ id="models.E021",
+ ),
+ ],
+ )
def test_non_valid(self):
class RelationModel(models.Model):
@@ -1019,62 +1176,74 @@ class OtherModelTests(SimpleTestCase):
relation = models.ManyToManyField(RelationModel)
class Meta:
- ordering = ['relation']
+ ordering = ["relation"]
- self.assertEqual(Model.check(), [
- Error(
- "'ordering' refers to the nonexistent field, related field, "
- "or lookup 'relation'.",
- obj=Model,
- id='models.E015',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'ordering' refers to the nonexistent field, related field, "
+ "or lookup 'relation'.",
+ obj=Model,
+ id="models.E015",
+ ),
+ ],
+ )
def test_ordering_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
- ordering = ('missing_field',)
+ ordering = ("missing_field",)
- self.assertEqual(Model.check(), [
- Error(
- "'ordering' refers to the nonexistent field, related field, "
- "or lookup 'missing_field'.",
- obj=Model,
- id='models.E015',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'ordering' refers to the nonexistent field, related field, "
+ "or lookup 'missing_field'.",
+ obj=Model,
+ id="models.E015",
+ )
+ ],
+ )
def test_ordering_pointing_to_missing_foreignkey_field(self):
class Model(models.Model):
missing_fk_field = models.IntegerField()
class Meta:
- ordering = ('missing_fk_field_id',)
+ ordering = ("missing_fk_field_id",)
- self.assertEqual(Model.check(), [
- Error(
- "'ordering' refers to the nonexistent field, related field, "
- "or lookup 'missing_fk_field_id'.",
- obj=Model,
- id='models.E015',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'ordering' refers to the nonexistent field, related field, "
+ "or lookup 'missing_fk_field_id'.",
+ obj=Model,
+ id="models.E015",
+ )
+ ],
+ )
def test_ordering_pointing_to_missing_related_field(self):
class Model(models.Model):
test = models.IntegerField()
class Meta:
- ordering = ('missing_related__id',)
+ ordering = ("missing_related__id",)
- self.assertEqual(Model.check(), [
- Error(
- "'ordering' refers to the nonexistent field, related field, "
- "or lookup 'missing_related__id'.",
- obj=Model,
- id='models.E015',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'ordering' refers to the nonexistent field, related field, "
+ "or lookup 'missing_related__id'.",
+ obj=Model,
+ id="models.E015",
+ )
+ ],
+ )
def test_ordering_pointing_to_missing_related_model_field(self):
class Parent(models.Model):
@@ -1084,32 +1253,38 @@ class OtherModelTests(SimpleTestCase):
parent = models.ForeignKey(Parent, models.CASCADE)
class Meta:
- ordering = ('parent__missing_field',)
+ ordering = ("parent__missing_field",)
- self.assertEqual(Child.check(), [
- Error(
- "'ordering' refers to the nonexistent field, related field, "
- "or lookup 'parent__missing_field'.",
- obj=Child,
- id='models.E015',
- )
- ])
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "'ordering' refers to the nonexistent field, related field, "
+ "or lookup 'parent__missing_field'.",
+ obj=Child,
+ id="models.E015",
+ )
+ ],
+ )
def test_ordering_pointing_to_non_related_field(self):
class Child(models.Model):
parent = models.IntegerField()
class Meta:
- ordering = ('parent__missing_field',)
+ ordering = ("parent__missing_field",)
- self.assertEqual(Child.check(), [
- Error(
- "'ordering' refers to the nonexistent field, related field, "
- "or lookup 'parent__missing_field'.",
- obj=Child,
- id='models.E015',
- )
- ])
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "'ordering' refers to the nonexistent field, related field, "
+ "or lookup 'parent__missing_field'.",
+ obj=Child,
+ id="models.E015",
+ )
+ ],
+ )
def test_ordering_pointing_to_two_related_model_field(self):
class Parent2(models.Model):
@@ -1122,16 +1297,19 @@ class OtherModelTests(SimpleTestCase):
parent1 = models.ForeignKey(Parent1, models.CASCADE)
class Meta:
- ordering = ('parent1__parent2__missing_field',)
+ ordering = ("parent1__parent2__missing_field",)
- self.assertEqual(Child.check(), [
- Error(
- "'ordering' refers to the nonexistent field, related field, "
- "or lookup 'parent1__parent2__missing_field'.",
- obj=Child,
- id='models.E015',
- )
- ])
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "'ordering' refers to the nonexistent field, related field, "
+ "or lookup 'parent1__parent2__missing_field'.",
+ obj=Child,
+ id="models.E015",
+ )
+ ],
+ )
def test_ordering_pointing_multiple_times_to_model_fields(self):
class Parent(models.Model):
@@ -1142,23 +1320,26 @@ class OtherModelTests(SimpleTestCase):
parent = models.ForeignKey(Parent, models.CASCADE)
class Meta:
- ordering = ('parent__field1__field2',)
+ ordering = ("parent__field1__field2",)
- self.assertEqual(Child.check(), [
- Error(
- "'ordering' refers to the nonexistent field, related field, "
- "or lookup 'parent__field1__field2'.",
- obj=Child,
- id='models.E015',
- )
- ])
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "'ordering' refers to the nonexistent field, related field, "
+ "or lookup 'parent__field1__field2'.",
+ obj=Child,
+ id="models.E015",
+ )
+ ],
+ )
def test_ordering_allows_registered_lookups(self):
class Model(models.Model):
test = models.CharField(max_length=100)
class Meta:
- ordering = ('test__lower',)
+ ordering = ("test__lower",)
with register_lookup(models.CharField, Lower):
self.assertEqual(Model.check(), [])
@@ -1168,7 +1349,7 @@ class OtherModelTests(SimpleTestCase):
test = models.CharField(max_length=100)
class Meta:
- ordering = ('test__isnull',)
+ ordering = ("test__isnull",)
self.assertEqual(Model.check(), [])
@@ -1180,7 +1361,7 @@ class OtherModelTests(SimpleTestCase):
parent = models.ForeignKey(Parent, models.CASCADE)
class Meta:
- ordering = ('parent__pk',)
+ ordering = ("parent__pk",)
self.assertEqual(Child.check(), [])
@@ -1192,7 +1373,7 @@ class OtherModelTests(SimpleTestCase):
parent = models.ForeignKey(Parent, models.CASCADE)
class Meta:
- ordering = ('parent_id',)
+ ordering = ("parent_id",)
self.assertFalse(Child.check())
@@ -1200,116 +1381,144 @@ class OtherModelTests(SimpleTestCase):
class _Model(models.Model):
pass
- self.assertEqual(_Model.check(), [
- Error(
- "The model name '_Model' cannot start or end with an underscore "
- "as it collides with the query lookup syntax.",
- obj=_Model,
- id='models.E023',
- )
- ])
+ self.assertEqual(
+ _Model.check(),
+ [
+ Error(
+ "The model name '_Model' cannot start or end with an underscore "
+ "as it collides with the query lookup syntax.",
+ obj=_Model,
+ id="models.E023",
+ )
+ ],
+ )
def test_name_ending_with_underscore(self):
class Model_(models.Model):
pass
- self.assertEqual(Model_.check(), [
- Error(
- "The model name 'Model_' cannot start or end with an underscore "
- "as it collides with the query lookup syntax.",
- obj=Model_,
- id='models.E023',
- )
- ])
+ self.assertEqual(
+ Model_.check(),
+ [
+ Error(
+ "The model name 'Model_' cannot start or end with an underscore "
+ "as it collides with the query lookup syntax.",
+ obj=Model_,
+ id="models.E023",
+ )
+ ],
+ )
def test_name_contains_double_underscores(self):
class Test__Model(models.Model):
pass
- self.assertEqual(Test__Model.check(), [
- Error(
- "The model name 'Test__Model' cannot contain double underscores "
- "as it collides with the query lookup syntax.",
- obj=Test__Model,
- id='models.E024',
- )
- ])
+ self.assertEqual(
+ Test__Model.check(),
+ [
+ Error(
+ "The model name 'Test__Model' cannot contain double underscores "
+ "as it collides with the query lookup syntax.",
+ obj=Test__Model,
+ id="models.E024",
+ )
+ ],
+ )
def test_property_and_related_field_accessor_clash(self):
class Model(models.Model):
- fk = models.ForeignKey('self', models.CASCADE)
+ fk = models.ForeignKey("self", models.CASCADE)
# Override related field accessor.
- Model.fk_id = property(lambda self: 'ERROR')
+ Model.fk_id = property(lambda self: "ERROR")
- self.assertEqual(Model.check(), [
- Error(
- "The property 'fk_id' clashes with a related field accessor.",
- obj=Model,
- id='models.E025',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "The property 'fk_id' clashes with a related field accessor.",
+ obj=Model,
+ id="models.E025",
+ )
+ ],
+ )
def test_single_primary_key(self):
class Model(models.Model):
foo = models.IntegerField(primary_key=True)
bar = models.IntegerField(primary_key=True)
- self.assertEqual(Model.check(), [
- Error(
- "The model cannot have more than one field with 'primary_key=True'.",
- obj=Model,
- id='models.E026',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "The model cannot have more than one field with 'primary_key=True'.",
+ obj=Model,
+ id="models.E026",
+ )
+ ],
+ )
- @override_settings(TEST_SWAPPED_MODEL_BAD_VALUE='not-a-model')
+ @override_settings(TEST_SWAPPED_MODEL_BAD_VALUE="not-a-model")
def test_swappable_missing_app_name(self):
class Model(models.Model):
class Meta:
- swappable = 'TEST_SWAPPED_MODEL_BAD_VALUE'
+ swappable = "TEST_SWAPPED_MODEL_BAD_VALUE"
- self.assertEqual(Model.check(), [
- Error(
- "'TEST_SWAPPED_MODEL_BAD_VALUE' is not of the form 'app_label.app_name'.",
- id='models.E001',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'TEST_SWAPPED_MODEL_BAD_VALUE' is not of the form 'app_label.app_name'.",
+ id="models.E001",
+ ),
+ ],
+ )
- @override_settings(TEST_SWAPPED_MODEL_BAD_MODEL='not_an_app.Target')
+ @override_settings(TEST_SWAPPED_MODEL_BAD_MODEL="not_an_app.Target")
def test_swappable_missing_app(self):
class Model(models.Model):
class Meta:
- swappable = 'TEST_SWAPPED_MODEL_BAD_MODEL'
+ swappable = "TEST_SWAPPED_MODEL_BAD_MODEL"
- self.assertEqual(Model.check(), [
- Error(
- "'TEST_SWAPPED_MODEL_BAD_MODEL' references 'not_an_app.Target', "
- 'which has not been installed, or is abstract.',
- id='models.E002',
- ),
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "'TEST_SWAPPED_MODEL_BAD_MODEL' references 'not_an_app.Target', "
+ "which has not been installed, or is abstract.",
+ id="models.E002",
+ ),
+ ],
+ )
def test_two_m2m_through_same_relationship(self):
class Person(models.Model):
pass
class Group(models.Model):
- primary = models.ManyToManyField(Person, through='Membership', related_name='primary')
- secondary = models.ManyToManyField(Person, through='Membership', related_name='secondary')
+ primary = models.ManyToManyField(
+ Person, through="Membership", related_name="primary"
+ )
+ secondary = models.ManyToManyField(
+ Person, through="Membership", related_name="secondary"
+ )
class Membership(models.Model):
person = models.ForeignKey(Person, models.CASCADE)
group = models.ForeignKey(Group, models.CASCADE)
- self.assertEqual(Group.check(), [
- Error(
- "The model has two identical many-to-many relations through "
- "the intermediate model 'invalid_models_tests.Membership'.",
- obj=Group,
- id='models.E003',
- )
- ])
+ self.assertEqual(
+ Group.check(),
+ [
+ Error(
+ "The model has two identical many-to-many relations through "
+ "the intermediate model 'invalid_models_tests.Membership'.",
+ obj=Group,
+ id="models.E003",
+ )
+ ],
+ )
def test_two_m2m_through_same_model_with_different_through_fields(self):
class Country(models.Model):
@@ -1317,13 +1526,15 @@ class OtherModelTests(SimpleTestCase):
class ShippingMethod(models.Model):
to_countries = models.ManyToManyField(
- Country, through='ShippingMethodPrice',
- through_fields=('method', 'to_country'),
+ Country,
+ through="ShippingMethodPrice",
+ through_fields=("method", "to_country"),
)
from_countries = models.ManyToManyField(
- Country, through='ShippingMethodPrice',
- through_fields=('method', 'from_country'),
- related_name='+',
+ Country,
+ through="ShippingMethodPrice",
+ through_fields=("method", "from_country"),
+ related_name="+",
)
class ShippingMethodPrice(models.Model):
@@ -1338,7 +1549,9 @@ class OtherModelTests(SimpleTestCase):
pass
class ParkingLot(Place):
- other_place = models.OneToOneField(Place, models.CASCADE, related_name='other_parking')
+ other_place = models.OneToOneField(
+ Place, models.CASCADE, related_name="other_parking"
+ )
self.assertEqual(ParkingLot.check(), [])
@@ -1347,162 +1560,190 @@ class OtherModelTests(SimpleTestCase):
pass
class ParkingLot(Place):
- place = models.OneToOneField(Place, models.CASCADE, parent_link=True, primary_key=True)
- other_place = models.OneToOneField(Place, models.CASCADE, related_name='other_parking')
+ place = models.OneToOneField(
+ Place, models.CASCADE, parent_link=True, primary_key=True
+ )
+ other_place = models.OneToOneField(
+ Place, models.CASCADE, related_name="other_parking"
+ )
self.assertEqual(ParkingLot.check(), [])
def test_m2m_table_name_clash(self):
class Foo(models.Model):
- bar = models.ManyToManyField('Bar', db_table='myapp_bar')
+ bar = models.ManyToManyField("Bar", db_table="myapp_bar")
class Meta:
- db_table = 'myapp_foo'
+ db_table = "myapp_foo"
class Bar(models.Model):
class Meta:
- db_table = 'myapp_bar'
+ db_table = "myapp_bar"
- self.assertEqual(Foo.check(), [
- Error(
- "The field's intermediary table 'myapp_bar' clashes with the "
- "table name of 'invalid_models_tests.Bar'.",
- obj=Foo._meta.get_field('bar'),
- id='fields.E340',
- )
- ])
+ self.assertEqual(
+ Foo.check(),
+ [
+ Error(
+ "The field's intermediary table 'myapp_bar' clashes with the "
+ "table name of 'invalid_models_tests.Bar'.",
+ obj=Foo._meta.get_field("bar"),
+ id="fields.E340",
+ )
+ ],
+ )
- @override_settings(DATABASE_ROUTERS=['invalid_models_tests.test_models.EmptyRouter'])
+ @override_settings(
+ DATABASE_ROUTERS=["invalid_models_tests.test_models.EmptyRouter"]
+ )
def test_m2m_table_name_clash_database_routers_installed(self):
class Foo(models.Model):
- bar = models.ManyToManyField('Bar', db_table='myapp_bar')
+ bar = models.ManyToManyField("Bar", db_table="myapp_bar")
class Meta:
- db_table = 'myapp_foo'
+ db_table = "myapp_foo"
class Bar(models.Model):
class Meta:
- db_table = 'myapp_bar'
-
- self.assertEqual(Foo.check(), [
- Warning(
- "The field's intermediary table 'myapp_bar' clashes with the "
- "table name of 'invalid_models_tests.Bar'.",
- obj=Foo._meta.get_field('bar'),
- hint=(
- "You have configured settings.DATABASE_ROUTERS. Verify "
- "that the table of 'invalid_models_tests.Bar' is "
- "correctly routed to a separate database."
+ db_table = "myapp_bar"
+
+ self.assertEqual(
+ Foo.check(),
+ [
+ Warning(
+ "The field's intermediary table 'myapp_bar' clashes with the "
+ "table name of 'invalid_models_tests.Bar'.",
+ obj=Foo._meta.get_field("bar"),
+ hint=(
+ "You have configured settings.DATABASE_ROUTERS. Verify "
+ "that the table of 'invalid_models_tests.Bar' is "
+ "correctly routed to a separate database."
+ ),
+ id="fields.W344",
),
- id='fields.W344',
- ),
- ])
+ ],
+ )
def test_m2m_field_table_name_clash(self):
class Foo(models.Model):
pass
class Bar(models.Model):
- foos = models.ManyToManyField(Foo, db_table='clash')
+ foos = models.ManyToManyField(Foo, db_table="clash")
class Baz(models.Model):
- foos = models.ManyToManyField(Foo, db_table='clash')
+ foos = models.ManyToManyField(Foo, db_table="clash")
- self.assertEqual(Bar.check() + Baz.check(), [
- Error(
- "The field's intermediary table 'clash' clashes with the "
- "table name of 'invalid_models_tests.Baz.foos'.",
- obj=Bar._meta.get_field('foos'),
- id='fields.E340',
- ),
- Error(
- "The field's intermediary table 'clash' clashes with the "
- "table name of 'invalid_models_tests.Bar.foos'.",
- obj=Baz._meta.get_field('foos'),
- id='fields.E340',
- )
- ])
+ self.assertEqual(
+ Bar.check() + Baz.check(),
+ [
+ Error(
+ "The field's intermediary table 'clash' clashes with the "
+ "table name of 'invalid_models_tests.Baz.foos'.",
+ obj=Bar._meta.get_field("foos"),
+ id="fields.E340",
+ ),
+ Error(
+ "The field's intermediary table 'clash' clashes with the "
+ "table name of 'invalid_models_tests.Bar.foos'.",
+ obj=Baz._meta.get_field("foos"),
+ id="fields.E340",
+ ),
+ ],
+ )
- @override_settings(DATABASE_ROUTERS=['invalid_models_tests.test_models.EmptyRouter'])
+ @override_settings(
+ DATABASE_ROUTERS=["invalid_models_tests.test_models.EmptyRouter"]
+ )
def test_m2m_field_table_name_clash_database_routers_installed(self):
class Foo(models.Model):
pass
class Bar(models.Model):
- foos = models.ManyToManyField(Foo, db_table='clash')
+ foos = models.ManyToManyField(Foo, db_table="clash")
class Baz(models.Model):
- foos = models.ManyToManyField(Foo, db_table='clash')
-
- self.assertEqual(Bar.check() + Baz.check(), [
- Warning(
- "The field's intermediary table 'clash' clashes with the "
- "table name of 'invalid_models_tests.%s.foos'."
- % clashing_model,
- obj=model_cls._meta.get_field('foos'),
- hint=(
- "You have configured settings.DATABASE_ROUTERS. Verify "
- "that the table of 'invalid_models_tests.%s.foos' is "
- "correctly routed to a separate database." % clashing_model
- ),
- id='fields.W344',
- ) for model_cls, clashing_model in [(Bar, 'Baz'), (Baz, 'Bar')]
- ])
+ foos = models.ManyToManyField(Foo, db_table="clash")
+
+ self.assertEqual(
+ Bar.check() + Baz.check(),
+ [
+ Warning(
+ "The field's intermediary table 'clash' clashes with the "
+ "table name of 'invalid_models_tests.%s.foos'." % clashing_model,
+ obj=model_cls._meta.get_field("foos"),
+ hint=(
+ "You have configured settings.DATABASE_ROUTERS. Verify "
+ "that the table of 'invalid_models_tests.%s.foos' is "
+ "correctly routed to a separate database." % clashing_model
+ ),
+ id="fields.W344",
+ )
+ for model_cls, clashing_model in [(Bar, "Baz"), (Baz, "Bar")]
+ ],
+ )
def test_m2m_autogenerated_table_name_clash(self):
class Foo(models.Model):
class Meta:
- db_table = 'bar_foos'
+ db_table = "bar_foos"
class Bar(models.Model):
# The autogenerated `db_table` will be bar_foos.
foos = models.ManyToManyField(Foo)
class Meta:
- db_table = 'bar'
+ db_table = "bar"
- self.assertEqual(Bar.check(), [
- Error(
- "The field's intermediary table 'bar_foos' clashes with the "
- "table name of 'invalid_models_tests.Foo'.",
- obj=Bar._meta.get_field('foos'),
- id='fields.E340',
- )
- ])
+ self.assertEqual(
+ Bar.check(),
+ [
+ Error(
+ "The field's intermediary table 'bar_foos' clashes with the "
+ "table name of 'invalid_models_tests.Foo'.",
+ obj=Bar._meta.get_field("foos"),
+ id="fields.E340",
+ )
+ ],
+ )
- @override_settings(DATABASE_ROUTERS=['invalid_models_tests.test_models.EmptyRouter'])
+ @override_settings(
+ DATABASE_ROUTERS=["invalid_models_tests.test_models.EmptyRouter"]
+ )
def test_m2m_autogenerated_table_name_clash_database_routers_installed(self):
class Foo(models.Model):
class Meta:
- db_table = 'bar_foos'
+ db_table = "bar_foos"
class Bar(models.Model):
# The autogenerated db_table is bar_foos.
foos = models.ManyToManyField(Foo)
class Meta:
- db_table = 'bar'
+ db_table = "bar"
- self.assertEqual(Bar.check(), [
- Warning(
- "The field's intermediary table 'bar_foos' clashes with the "
- "table name of 'invalid_models_tests.Foo'.",
- obj=Bar._meta.get_field('foos'),
- hint=(
- "You have configured settings.DATABASE_ROUTERS. Verify "
- "that the table of 'invalid_models_tests.Foo' is "
- "correctly routed to a separate database."
+ self.assertEqual(
+ Bar.check(),
+ [
+ Warning(
+ "The field's intermediary table 'bar_foos' clashes with the "
+ "table name of 'invalid_models_tests.Foo'.",
+ obj=Bar._meta.get_field("foos"),
+ hint=(
+ "You have configured settings.DATABASE_ROUTERS. Verify "
+ "that the table of 'invalid_models_tests.Foo' is "
+ "correctly routed to a separate database."
+ ),
+ id="fields.W344",
),
- id='fields.W344',
- ),
- ])
+ ],
+ )
def test_m2m_unmanaged_shadow_models_not_checked(self):
class A1(models.Model):
pass
class C1(models.Model):
- mm_a = models.ManyToManyField(A1, db_table='d1')
+ mm_a = models.ManyToManyField(A1, db_table="d1")
# Unmanaged models that shadow the above models. Reused table names
# shouldn't be flagged by any checks.
@@ -1511,17 +1752,17 @@ class OtherModelTests(SimpleTestCase):
managed = False
class C2(models.Model):
- mm_a = models.ManyToManyField(A2, through='Intermediate')
+ mm_a = models.ManyToManyField(A2, through="Intermediate")
class Meta:
managed = False
class Intermediate(models.Model):
- a2 = models.ForeignKey(A2, models.CASCADE, db_column='a1_id')
- c2 = models.ForeignKey(C2, models.CASCADE, db_column='c1_id')
+ a2 = models.ForeignKey(A2, models.CASCADE, db_column="a1_id")
+ c2 = models.ForeignKey(C2, models.CASCADE, db_column="c1_id")
class Meta:
- db_table = 'd1'
+ db_table = "d1"
managed = False
self.assertEqual(C1.check(), [])
@@ -1532,8 +1773,8 @@ class OtherModelTests(SimpleTestCase):
pass
class Through(models.Model):
- a = models.ForeignKey('A', models.CASCADE)
- c = models.ForeignKey('C', models.CASCADE)
+ a = models.ForeignKey("A", models.CASCADE)
+ c = models.ForeignKey("C", models.CASCADE)
class ThroughProxy(Through):
class Meta:
@@ -1541,17 +1782,19 @@ class OtherModelTests(SimpleTestCase):
class C(models.Model):
mm_a = models.ManyToManyField(A, through=Through)
- mm_aproxy = models.ManyToManyField(A, through=ThroughProxy, related_name='proxied_m2m')
+ mm_aproxy = models.ManyToManyField(
+ A, through=ThroughProxy, related_name="proxied_m2m"
+ )
self.assertEqual(C.check(), [])
- @isolate_apps('django.contrib.auth', kwarg_name='apps')
+ @isolate_apps("django.contrib.auth", kwarg_name="apps")
def test_lazy_reference_checks(self, apps):
class DummyModel(models.Model):
- author = models.ForeignKey('Author', models.CASCADE)
+ author = models.ForeignKey("Author", models.CASCADE)
class Meta:
- app_label = 'invalid_models_tests'
+ app_label = "invalid_models_tests"
class DummyClass:
def __call__(self, **kwargs):
@@ -1563,59 +1806,65 @@ class OtherModelTests(SimpleTestCase):
def dummy_function(*args, **kwargs):
pass
- apps.lazy_model_operation(dummy_function, ('auth', 'imaginarymodel'))
- apps.lazy_model_operation(dummy_function, ('fanciful_app', 'imaginarymodel'))
+ apps.lazy_model_operation(dummy_function, ("auth", "imaginarymodel"))
+ apps.lazy_model_operation(dummy_function, ("fanciful_app", "imaginarymodel"))
- post_init.connect(dummy_function, sender='missing-app.Model', apps=apps)
- post_init.connect(DummyClass(), sender='missing-app.Model', apps=apps)
- post_init.connect(DummyClass().dummy_method, sender='missing-app.Model', apps=apps)
+ post_init.connect(dummy_function, sender="missing-app.Model", apps=apps)
+ post_init.connect(DummyClass(), sender="missing-app.Model", apps=apps)
+ post_init.connect(
+ DummyClass().dummy_method, sender="missing-app.Model", apps=apps
+ )
- self.assertEqual(_check_lazy_references(apps), [
- Error(
- "%r contains a lazy reference to auth.imaginarymodel, "
- "but app 'auth' doesn't provide model 'imaginarymodel'." % dummy_function,
- obj=dummy_function,
- id='models.E022',
- ),
- Error(
- "%r contains a lazy reference to fanciful_app.imaginarymodel, "
- "but app 'fanciful_app' isn't installed." % dummy_function,
- obj=dummy_function,
- id='models.E022',
- ),
- Error(
- "An instance of class 'DummyClass' was connected to "
- "the 'post_init' signal with a lazy reference to the sender "
- "'missing-app.model', but app 'missing-app' isn't installed.",
- hint=None,
- obj='invalid_models_tests.test_models',
- id='signals.E001',
- ),
- Error(
- "Bound method 'DummyClass.dummy_method' was connected to the "
- "'post_init' signal with a lazy reference to the sender "
- "'missing-app.model', but app 'missing-app' isn't installed.",
- hint=None,
- obj='invalid_models_tests.test_models',
- id='signals.E001',
- ),
- Error(
- "The field invalid_models_tests.DummyModel.author was declared "
- "with a lazy reference to 'invalid_models_tests.author', but app "
- "'invalid_models_tests' isn't installed.",
- hint=None,
- obj=DummyModel.author.field,
- id='fields.E307',
- ),
- Error(
- "The function 'dummy_function' was connected to the 'post_init' "
- "signal with a lazy reference to the sender "
- "'missing-app.model', but app 'missing-app' isn't installed.",
- hint=None,
- obj='invalid_models_tests.test_models',
- id='signals.E001',
- ),
- ])
+ self.assertEqual(
+ _check_lazy_references(apps),
+ [
+ Error(
+ "%r contains a lazy reference to auth.imaginarymodel, "
+ "but app 'auth' doesn't provide model 'imaginarymodel'."
+ % dummy_function,
+ obj=dummy_function,
+ id="models.E022",
+ ),
+ Error(
+ "%r contains a lazy reference to fanciful_app.imaginarymodel, "
+ "but app 'fanciful_app' isn't installed." % dummy_function,
+ obj=dummy_function,
+ id="models.E022",
+ ),
+ Error(
+ "An instance of class 'DummyClass' was connected to "
+ "the 'post_init' signal with a lazy reference to the sender "
+ "'missing-app.model', but app 'missing-app' isn't installed.",
+ hint=None,
+ obj="invalid_models_tests.test_models",
+ id="signals.E001",
+ ),
+ Error(
+ "Bound method 'DummyClass.dummy_method' was connected to the "
+ "'post_init' signal with a lazy reference to the sender "
+ "'missing-app.model', but app 'missing-app' isn't installed.",
+ hint=None,
+ obj="invalid_models_tests.test_models",
+ id="signals.E001",
+ ),
+ Error(
+ "The field invalid_models_tests.DummyModel.author was declared "
+ "with a lazy reference to 'invalid_models_tests.author', but app "
+ "'invalid_models_tests' isn't installed.",
+ hint=None,
+ obj=DummyModel.author.field,
+ id="fields.E307",
+ ),
+ Error(
+ "The function 'dummy_function' was connected to the 'post_init' "
+ "signal with a lazy reference to the sender "
+ "'missing-app.model', but app 'missing-app' isn't installed.",
+ hint=None,
+ obj="invalid_models_tests.test_models",
+ id="signals.E001",
+ ),
+ ],
+ )
class MultipleAutoFieldsTests(TestCase):
@@ -1625,20 +1874,21 @@ class MultipleAutoFieldsTests(TestCase):
"than one auto-generated field."
)
with self.assertRaisesMessage(ValueError, msg):
+
class MultipleAutoFields(models.Model):
auto1 = models.AutoField(primary_key=True)
auto2 = models.AutoField(primary_key=True)
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class JSONFieldTests(TestCase):
- @skipUnlessDBFeature('supports_json_field')
+ @skipUnlessDBFeature("supports_json_field")
def test_ordering_pointing_to_json_field_value(self):
class Model(models.Model):
field = models.JSONField()
class Meta:
- ordering = ['field__value']
+ ordering = ["field__value"]
self.assertEqual(Model.check(databases=self.databases), [])
@@ -1647,9 +1897,9 @@ class JSONFieldTests(TestCase):
field = models.JSONField()
error = Error(
- '%s does not support JSONFields.' % connection.display_name,
+ "%s does not support JSONFields." % connection.display_name,
obj=Model,
- id='fields.E180',
+ id="fields.E180",
)
expected = [] if connection.features.supports_json_field else [error]
self.assertEqual(Model.check(databases=self.databases), expected)
@@ -1659,31 +1909,35 @@ class JSONFieldTests(TestCase):
field = models.JSONField()
class Meta:
- required_db_features = {'supports_json_field'}
+ required_db_features = {"supports_json_field"}
self.assertEqual(Model.check(databases=self.databases), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class ConstraintsTests(TestCase):
def test_check_constraints(self):
class Model(models.Model):
age = models.IntegerField()
class Meta:
- constraints = [models.CheckConstraint(check=models.Q(age__gte=18), name='is_adult')]
+ constraints = [
+ models.CheckConstraint(check=models.Q(age__gte=18), name="is_adult")
+ ]
errors = Model.check(databases=self.databases)
warn = Warning(
- '%s does not support check constraints.' % connection.display_name,
+ "%s does not support check constraints." % connection.display_name,
hint=(
"A constraint won't be created. Silence this warning if you "
"don't care about it."
),
obj=Model,
- id='models.W027',
+ id="models.W027",
+ )
+ expected = (
+ [] if connection.features.supports_table_check_constraints else [warn]
)
- expected = [] if connection.features.supports_table_check_constraints else [warn]
self.assertCountEqual(errors, expected)
def test_check_constraints_required_db_features(self):
@@ -1691,106 +1945,124 @@ class ConstraintsTests(TestCase):
age = models.IntegerField()
class Meta:
- required_db_features = {'supports_table_check_constraints'}
- constraints = [models.CheckConstraint(check=models.Q(age__gte=18), name='is_adult')]
+ required_db_features = {"supports_table_check_constraints"}
+ constraints = [
+ models.CheckConstraint(check=models.Q(age__gte=18), name="is_adult")
+ ]
+
self.assertEqual(Model.check(databases=self.databases), [])
def test_check_constraint_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
- required_db_features = {'supports_table_check_constraints'}
+ required_db_features = {"supports_table_check_constraints"}
constraints = [
models.CheckConstraint(
- name='name', check=models.Q(missing_field=2),
+ name="name",
+ check=models.Q(missing_field=2),
),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ] if connection.features.supports_table_check_constraints else [])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ]
+ if connection.features.supports_table_check_constraints
+ else [],
+ )
- @skipUnlessDBFeature('supports_table_check_constraints')
+ @skipUnlessDBFeature("supports_table_check_constraints")
def test_check_constraint_pointing_to_reverse_fk(self):
class Model(models.Model):
- parent = models.ForeignKey('self', models.CASCADE, related_name='parents')
+ parent = models.ForeignKey("self", models.CASCADE, related_name="parents")
class Meta:
constraints = [
- models.CheckConstraint(name='name', check=models.Q(parents=3)),
+ models.CheckConstraint(name="name", check=models.Q(parents=3)),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the nonexistent field 'parents'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the nonexistent field 'parents'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_table_check_constraints')
+ @skipUnlessDBFeature("supports_table_check_constraints")
def test_check_constraint_pointing_to_reverse_o2o(self):
class Model(models.Model):
- parent = models.OneToOneField('self', models.CASCADE)
+ parent = models.OneToOneField("self", models.CASCADE)
class Meta:
constraints = [
models.CheckConstraint(
- name='name',
+ name="name",
check=models.Q(model__isnull=True),
),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the nonexistent field 'model'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the nonexistent field 'model'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_table_check_constraints')
+ @skipUnlessDBFeature("supports_table_check_constraints")
def test_check_constraint_pointing_to_m2m_field(self):
class Model(models.Model):
- m2m = models.ManyToManyField('self')
+ m2m = models.ManyToManyField("self")
class Meta:
constraints = [
- models.CheckConstraint(name='name', check=models.Q(m2m=2)),
+ models.CheckConstraint(name="name", check=models.Q(m2m=2)),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to a ManyToManyField 'm2m', but "
- "ManyToManyFields are not permitted in 'constraints'.",
- obj=Model,
- id='models.E013',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to a ManyToManyField 'm2m', but "
+ "ManyToManyFields are not permitted in 'constraints'.",
+ obj=Model,
+ id="models.E013",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_table_check_constraints')
+ @skipUnlessDBFeature("supports_table_check_constraints")
def test_check_constraint_pointing_to_fk(self):
class Target(models.Model):
pass
class Model(models.Model):
- fk_1 = models.ForeignKey(Target, models.CASCADE, related_name='target_1')
- fk_2 = models.ForeignKey(Target, models.CASCADE, related_name='target_2')
+ fk_1 = models.ForeignKey(Target, models.CASCADE, related_name="target_1")
+ fk_2 = models.ForeignKey(Target, models.CASCADE, related_name="target_2")
class Meta:
constraints = [
models.CheckConstraint(
- name='name',
+ name="name",
check=models.Q(fk_1_id=2) | models.Q(fk_2=2),
),
]
self.assertEqual(Model.check(databases=self.databases), [])
- @skipUnlessDBFeature('supports_table_check_constraints')
+ @skipUnlessDBFeature("supports_table_check_constraints")
def test_check_constraint_pointing_to_pk(self):
class Model(models.Model):
age = models.SmallIntegerField()
@@ -1798,14 +2070,14 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
models.CheckConstraint(
- name='name',
- check=models.Q(pk__gt=5) & models.Q(age__gt=models.F('pk')),
+ name="name",
+ check=models.Q(pk__gt=5) & models.Q(age__gt=models.F("pk")),
),
]
self.assertEqual(Model.check(databases=self.databases), [])
- @skipUnlessDBFeature('supports_table_check_constraints')
+ @skipUnlessDBFeature("supports_table_check_constraints")
def test_check_constraint_pointing_to_non_local_field(self):
class Parent(models.Model):
field1 = models.IntegerField()
@@ -1815,99 +2087,111 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
- models.CheckConstraint(name='name', check=models.Q(field1=1)),
+ models.CheckConstraint(name="name", check=models.Q(field1=1)),
]
- self.assertEqual(Child.check(databases=self.databases), [
- Error(
- "'constraints' refers to field 'field1' which is not local to "
- "model 'Child'.",
- hint='This issue may be caused by multi-table inheritance.',
- obj=Child,
- id='models.E016',
- ),
- ])
+ self.assertEqual(
+ Child.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to field 'field1' which is not local to "
+ "model 'Child'.",
+ hint="This issue may be caused by multi-table inheritance.",
+ obj=Child,
+ id="models.E016",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_table_check_constraints')
+ @skipUnlessDBFeature("supports_table_check_constraints")
def test_check_constraint_pointing_to_joined_fields(self):
class Model(models.Model):
name = models.CharField(max_length=10)
field1 = models.PositiveSmallIntegerField()
field2 = models.PositiveSmallIntegerField()
field3 = models.PositiveSmallIntegerField()
- parent = models.ForeignKey('self', models.CASCADE)
- previous = models.OneToOneField('self', models.CASCADE, related_name='next')
+ parent = models.ForeignKey("self", models.CASCADE)
+ previous = models.OneToOneField("self", models.CASCADE, related_name="next")
class Meta:
constraints = [
models.CheckConstraint(
- name='name1', check=models.Q(
- field1__lt=models.F('parent__field1') + models.F('parent__field2')
- )
+ name="name1",
+ check=models.Q(
+ field1__lt=models.F("parent__field1")
+ + models.F("parent__field2")
+ ),
),
models.CheckConstraint(
- name='name2', check=models.Q(name=Lower('parent__name'))
+ name="name2", check=models.Q(name=Lower("parent__name"))
),
models.CheckConstraint(
- name='name3', check=models.Q(parent__field3=models.F('field1'))
+ name="name3", check=models.Q(parent__field3=models.F("field1"))
),
models.CheckConstraint(
- name='name4', check=models.Q(name=Lower('previous__name')),
+ name="name4",
+ check=models.Q(name=Lower("previous__name")),
),
]
joined_fields = [
- 'parent__field1',
- 'parent__field2',
- 'parent__field3',
- 'parent__name',
- 'previous__name',
+ "parent__field1",
+ "parent__field2",
+ "parent__field3",
+ "parent__name",
+ "previous__name",
]
errors = Model.check(databases=self.databases)
expected_errors = [
Error(
"'constraints' refers to the joined field '%s'." % field_name,
obj=Model,
- id='models.E041',
- ) for field_name in joined_fields
+ id="models.E041",
+ )
+ for field_name in joined_fields
]
self.assertCountEqual(errors, expected_errors)
- @skipUnlessDBFeature('supports_table_check_constraints')
+ @skipUnlessDBFeature("supports_table_check_constraints")
def test_check_constraint_pointing_to_joined_fields_complex_check(self):
class Model(models.Model):
name = models.PositiveSmallIntegerField()
field1 = models.PositiveSmallIntegerField()
field2 = models.PositiveSmallIntegerField()
- parent = models.ForeignKey('self', models.CASCADE)
+ parent = models.ForeignKey("self", models.CASCADE)
class Meta:
constraints = [
models.CheckConstraint(
- name='name',
+ name="name",
check=models.Q(
(
- models.Q(name='test') &
- models.Q(field1__lt=models.F('parent__field1'))
- ) |
- (
- models.Q(name__startswith=Lower('parent__name')) &
- models.Q(field1__gte=(
- models.F('parent__field1') + models.F('parent__field2')
- ))
+ models.Q(name="test")
+ & models.Q(field1__lt=models.F("parent__field1"))
+ )
+ | (
+ models.Q(name__startswith=Lower("parent__name"))
+ & models.Q(
+ field1__gte=(
+ models.F("parent__field1")
+ + models.F("parent__field2")
+ )
+ )
)
- ) | (models.Q(name='test1'))
+ )
+ | (models.Q(name="test1")),
),
]
- joined_fields = ['parent__field1', 'parent__field2', 'parent__name']
+ joined_fields = ["parent__field1", "parent__field2", "parent__name"]
errors = Model.check(databases=self.databases)
expected_errors = [
Error(
"'constraints' refers to the joined field '%s'." % field_name,
obj=Model,
- id='models.E041',
- ) for field_name in joined_fields
+ id="models.E041",
+ )
+ for field_name in joined_fields
]
self.assertCountEqual(errors, expected_errors)
@@ -1918,25 +2202,29 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['age'],
- name='unique_age_gte_100',
+ fields=["age"],
+ name="unique_age_gte_100",
condition=models.Q(age__gte=100),
),
]
errors = Model.check(databases=self.databases)
- expected = [] if connection.features.supports_partial_indexes else [
- Warning(
- '%s does not support unique constraints with conditions.'
- % connection.display_name,
- hint=(
- "A constraint won't be created. Silence this warning if "
- "you don't care about it."
+ expected = (
+ []
+ if connection.features.supports_partial_indexes
+ else [
+ Warning(
+ "%s does not support unique constraints with conditions."
+ % connection.display_name,
+ hint=(
+ "A constraint won't be created. Silence this warning if "
+ "you don't care about it."
+ ),
+ obj=Model,
+ id="models.W036",
),
- obj=Model,
- id='models.W036',
- ),
- ]
+ ]
+ )
self.assertEqual(errors, expected)
def test_unique_constraint_with_condition_required_db_features(self):
@@ -1944,11 +2232,11 @@ class ConstraintsTests(TestCase):
age = models.IntegerField()
class Meta:
- required_db_features = {'supports_partial_indexes'}
+ required_db_features = {"supports_partial_indexes"}
constraints = [
models.UniqueConstraint(
- fields=['age'],
- name='unique_age_gte_100',
+ fields=["age"],
+ name="unique_age_gte_100",
condition=models.Q(age__gte=100),
),
]
@@ -1960,67 +2248,82 @@ class ConstraintsTests(TestCase):
age = models.SmallIntegerField()
class Meta:
- required_db_features = {'supports_partial_indexes'}
+ required_db_features = {"supports_partial_indexes"}
constraints = [
models.UniqueConstraint(
- name='name',
- fields=['age'],
+ name="name",
+ fields=["age"],
condition=models.Q(missing_field=2),
),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ] if connection.features.supports_partial_indexes else [])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ]
+ if connection.features.supports_partial_indexes
+ else [],
+ )
def test_unique_constraint_condition_pointing_to_joined_fields(self):
class Model(models.Model):
age = models.SmallIntegerField()
- parent = models.ForeignKey('self', models.CASCADE)
+ parent = models.ForeignKey("self", models.CASCADE)
class Meta:
- required_db_features = {'supports_partial_indexes'}
+ required_db_features = {"supports_partial_indexes"}
constraints = [
models.UniqueConstraint(
- name='name',
- fields=['age'],
+ name="name",
+ fields=["age"],
condition=models.Q(parent__age__lt=2),
),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the joined field 'parent__age__lt'.",
- obj=Model,
- id='models.E041',
- )
- ] if connection.features.supports_partial_indexes else [])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the joined field 'parent__age__lt'.",
+ obj=Model,
+ id="models.E041",
+ )
+ ]
+ if connection.features.supports_partial_indexes
+ else [],
+ )
def test_unique_constraint_pointing_to_reverse_o2o(self):
class Model(models.Model):
- parent = models.OneToOneField('self', models.CASCADE)
+ parent = models.OneToOneField("self", models.CASCADE)
class Meta:
- required_db_features = {'supports_partial_indexes'}
+ required_db_features = {"supports_partial_indexes"}
constraints = [
models.UniqueConstraint(
- fields=['parent'],
- name='name',
+ fields=["parent"],
+ name="name",
condition=models.Q(model__isnull=True),
),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the nonexistent field 'model'.",
- obj=Model,
- id='models.E012',
- ),
- ] if connection.features.supports_partial_indexes else [])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the nonexistent field 'model'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ]
+ if connection.features.supports_partial_indexes
+ else [],
+ )
def test_deferrable_unique_constraint(self):
class Model(models.Model):
@@ -2029,25 +2332,29 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['age'],
- name='unique_age_deferrable',
+ fields=["age"],
+ name="unique_age_deferrable",
deferrable=models.Deferrable.DEFERRED,
),
]
errors = Model.check(databases=self.databases)
- expected = [] if connection.features.supports_deferrable_unique_constraints else [
- Warning(
- '%s does not support deferrable unique constraints.'
- % connection.display_name,
- hint=(
- "A constraint won't be created. Silence this warning if "
- "you don't care about it."
+ expected = (
+ []
+ if connection.features.supports_deferrable_unique_constraints
+ else [
+ Warning(
+ "%s does not support deferrable unique constraints."
+ % connection.display_name,
+ hint=(
+ "A constraint won't be created. Silence this warning if "
+ "you don't care about it."
+ ),
+ obj=Model,
+ id="models.W038",
),
- obj=Model,
- id='models.W038',
- ),
- ]
+ ]
+ )
self.assertEqual(errors, expected)
def test_deferrable_unique_constraint_required_db_features(self):
@@ -2055,11 +2362,11 @@ class ConstraintsTests(TestCase):
age = models.IntegerField()
class Meta:
- required_db_features = {'supports_deferrable_unique_constraints'}
+ required_db_features = {"supports_deferrable_unique_constraints"}
constraints = [
models.UniqueConstraint(
- fields=['age'],
- name='unique_age_deferrable',
+ fields=["age"],
+ name="unique_age_deferrable",
deferrable=models.Deferrable.IMMEDIATE,
),
]
@@ -2069,31 +2376,39 @@ class ConstraintsTests(TestCase):
def test_unique_constraint_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
- constraints = [models.UniqueConstraint(fields=['missing_field'], name='name')]
+ constraints = [
+ models.UniqueConstraint(fields=["missing_field"], name="name")
+ ]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
def test_unique_constraint_pointing_to_m2m_field(self):
class Model(models.Model):
- m2m = models.ManyToManyField('self')
+ m2m = models.ManyToManyField("self")
class Meta:
- constraints = [models.UniqueConstraint(fields=['m2m'], name='name')]
+ constraints = [models.UniqueConstraint(fields=["m2m"], name="name")]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to a ManyToManyField 'm2m', but "
- "ManyToManyFields are not permitted in 'constraints'.",
- obj=Model,
- id='models.E013',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to a ManyToManyField 'm2m', but "
+ "ManyToManyFields are not permitted in 'constraints'.",
+ obj=Model,
+ id="models.E013",
+ ),
+ ],
+ )
def test_unique_constraint_pointing_to_non_local_field(self):
class Parent(models.Model):
@@ -2104,30 +2419,33 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
- models.UniqueConstraint(fields=['field2', 'field1'], name='name'),
+ models.UniqueConstraint(fields=["field2", "field1"], name="name"),
]
- self.assertEqual(Child.check(databases=self.databases), [
- Error(
- "'constraints' refers to field 'field1' which is not local to "
- "model 'Child'.",
- hint='This issue may be caused by multi-table inheritance.',
- obj=Child,
- id='models.E016',
- ),
- ])
+ self.assertEqual(
+ Child.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to field 'field1' which is not local to "
+ "model 'Child'.",
+ hint="This issue may be caused by multi-table inheritance.",
+ obj=Child,
+ id="models.E016",
+ ),
+ ],
+ )
def test_unique_constraint_pointing_to_fk(self):
class Target(models.Model):
pass
class Model(models.Model):
- fk_1 = models.ForeignKey(Target, models.CASCADE, related_name='target_1')
- fk_2 = models.ForeignKey(Target, models.CASCADE, related_name='target_2')
+ fk_1 = models.ForeignKey(Target, models.CASCADE, related_name="target_1")
+ fk_2 = models.ForeignKey(Target, models.CASCADE, related_name="target_2")
class Meta:
constraints = [
- models.UniqueConstraint(fields=['fk_1_id', 'fk_2'], name='name'),
+ models.UniqueConstraint(fields=["fk_1_id", "fk_2"], name="name"),
]
self.assertEqual(Model.check(databases=self.databases), [])
@@ -2139,25 +2457,29 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['age'],
- name='unique_age_include_id',
- include=['id'],
+ fields=["age"],
+ name="unique_age_include_id",
+ include=["id"],
),
]
errors = Model.check(databases=self.databases)
- expected = [] if connection.features.supports_covering_indexes else [
- Warning(
- '%s does not support unique constraints with non-key columns.'
- % connection.display_name,
- hint=(
- "A constraint won't be created. Silence this warning if "
- "you don't care about it."
+ expected = (
+ []
+ if connection.features.supports_covering_indexes
+ else [
+ Warning(
+ "%s does not support unique constraints with non-key columns."
+ % connection.display_name,
+ hint=(
+ "A constraint won't be created. Silence this warning if "
+ "you don't care about it."
+ ),
+ obj=Model,
+ id="models.W039",
),
- obj=Model,
- id='models.W039',
- ),
- ]
+ ]
+ )
self.assertEqual(errors, expected)
def test_unique_constraint_with_include_required_db_features(self):
@@ -2165,61 +2487,67 @@ class ConstraintsTests(TestCase):
age = models.IntegerField()
class Meta:
- required_db_features = {'supports_covering_indexes'}
+ required_db_features = {"supports_covering_indexes"}
constraints = [
models.UniqueConstraint(
- fields=['age'],
- name='unique_age_include_id',
- include=['id'],
+ fields=["age"],
+ name="unique_age_include_id",
+ include=["id"],
),
]
self.assertEqual(Model.check(databases=self.databases), [])
- @skipUnlessDBFeature('supports_covering_indexes')
+ @skipUnlessDBFeature("supports_covering_indexes")
def test_unique_constraint_include_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['id'],
- include=['missing_field'],
- name='name',
+ fields=["id"],
+ include=["missing_field"],
+ name="name",
),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_covering_indexes')
+ @skipUnlessDBFeature("supports_covering_indexes")
def test_unique_constraint_include_pointing_to_m2m_field(self):
class Model(models.Model):
- m2m = models.ManyToManyField('self')
+ m2m = models.ManyToManyField("self")
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['id'],
- include=['m2m'],
- name='name',
+ fields=["id"],
+ include=["m2m"],
+ name="name",
),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to a ManyToManyField 'm2m', but "
- "ManyToManyFields are not permitted in 'constraints'.",
- obj=Model,
- id='models.E013',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to a ManyToManyField 'm2m', but "
+ "ManyToManyFields are not permitted in 'constraints'.",
+ obj=Model,
+ id="models.E013",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_covering_indexes')
+ @skipUnlessDBFeature("supports_covering_indexes")
def test_unique_constraint_include_pointing_to_non_local_field(self):
class Parent(models.Model):
field1 = models.IntegerField()
@@ -2230,37 +2558,40 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['field2'],
- include=['field1'],
- name='name',
+ fields=["field2"],
+ include=["field1"],
+ name="name",
),
]
- self.assertEqual(Child.check(databases=self.databases), [
- Error(
- "'constraints' refers to field 'field1' which is not local to "
- "model 'Child'.",
- hint='This issue may be caused by multi-table inheritance.',
- obj=Child,
- id='models.E016',
- ),
- ])
+ self.assertEqual(
+ Child.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to field 'field1' which is not local to "
+ "model 'Child'.",
+ hint="This issue may be caused by multi-table inheritance.",
+ obj=Child,
+ id="models.E016",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_covering_indexes')
+ @skipUnlessDBFeature("supports_covering_indexes")
def test_unique_constraint_include_pointing_to_fk(self):
class Target(models.Model):
pass
class Model(models.Model):
- fk_1 = models.ForeignKey(Target, models.CASCADE, related_name='target_1')
- fk_2 = models.ForeignKey(Target, models.CASCADE, related_name='target_2')
+ fk_1 = models.ForeignKey(Target, models.CASCADE, related_name="target_1")
+ fk_2 = models.ForeignKey(Target, models.CASCADE, related_name="target_2")
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['id'],
- include=['fk_1_id', 'fk_2'],
- name='name',
+ fields=["id"],
+ include=["fk_1_id", "fk_2"],
+ name="name",
),
]
@@ -2272,18 +2603,18 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
- models.UniqueConstraint(Lower('name'), name='lower_name_uq'),
+ models.UniqueConstraint(Lower("name"), name="lower_name_uq"),
]
warn = Warning(
- '%s does not support unique constraints on expressions.'
+ "%s does not support unique constraints on expressions."
% connection.display_name,
hint=(
"A constraint won't be created. Silence this warning if you "
"don't care about it."
),
obj=Model,
- id='models.W044',
+ id="models.W044",
)
expected = [] if connection.features.supports_expression_indexes else [warn]
self.assertEqual(Model.check(databases=self.databases), expected)
@@ -2294,13 +2625,13 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
- models.UniqueConstraint(Lower('name'), name='lower_name_unq'),
+ models.UniqueConstraint(Lower("name"), name="lower_name_unq"),
]
- required_db_features = {'supports_expression_indexes'}
+ required_db_features = {"supports_expression_indexes"}
self.assertEqual(Model.check(databases=self.databases), [])
- @skipUnlessDBFeature('supports_expression_indexes')
+ @skipUnlessDBFeature("supports_expression_indexes")
def test_func_unique_constraint_expression_custom_lookup(self):
class Model(models.Model):
height = models.IntegerField()
@@ -2309,97 +2640,110 @@ class ConstraintsTests(TestCase):
class Meta:
constraints = [
models.UniqueConstraint(
- models.F('height') / (models.F('weight__abs') + models.Value(5)),
- name='name',
+ models.F("height")
+ / (models.F("weight__abs") + models.Value(5)),
+ name="name",
),
]
with register_lookup(models.IntegerField, Abs):
self.assertEqual(Model.check(databases=self.databases), [])
- @skipUnlessDBFeature('supports_expression_indexes')
+ @skipUnlessDBFeature("supports_expression_indexes")
def test_func_unique_constraint_pointing_to_missing_field(self):
class Model(models.Model):
class Meta:
constraints = [
- models.UniqueConstraint(Lower('missing_field').desc(), name='name'),
+ models.UniqueConstraint(Lower("missing_field").desc(), name="name"),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_expression_indexes')
+ @skipUnlessDBFeature("supports_expression_indexes")
def test_func_unique_constraint_pointing_to_missing_field_nested(self):
class Model(models.Model):
class Meta:
constraints = [
- models.UniqueConstraint(Abs(Round('missing_field')), name='name'),
+ models.UniqueConstraint(Abs(Round("missing_field")), name="name"),
]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to the nonexistent field 'missing_field'.",
- obj=Model,
- id='models.E012',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to the nonexistent field 'missing_field'.",
+ obj=Model,
+ id="models.E012",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_expression_indexes')
+ @skipUnlessDBFeature("supports_expression_indexes")
def test_func_unique_constraint_pointing_to_m2m_field(self):
class Model(models.Model):
- m2m = models.ManyToManyField('self')
+ m2m = models.ManyToManyField("self")
class Meta:
- constraints = [models.UniqueConstraint(Lower('m2m'), name='name')]
+ constraints = [models.UniqueConstraint(Lower("m2m"), name="name")]
- self.assertEqual(Model.check(databases=self.databases), [
- Error(
- "'constraints' refers to a ManyToManyField 'm2m', but "
- "ManyToManyFields are not permitted in 'constraints'.",
- obj=Model,
- id='models.E013',
- ),
- ])
+ self.assertEqual(
+ Model.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to a ManyToManyField 'm2m', but "
+ "ManyToManyFields are not permitted in 'constraints'.",
+ obj=Model,
+ id="models.E013",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_expression_indexes')
+ @skipUnlessDBFeature("supports_expression_indexes")
def test_func_unique_constraint_pointing_to_non_local_field(self):
class Foo(models.Model):
field1 = models.CharField(max_length=15)
class Bar(Foo):
class Meta:
- constraints = [models.UniqueConstraint(Lower('field1'), name='name')]
+ constraints = [models.UniqueConstraint(Lower("field1"), name="name")]
- self.assertEqual(Bar.check(databases=self.databases), [
- Error(
- "'constraints' refers to field 'field1' which is not local to "
- "model 'Bar'.",
- hint='This issue may be caused by multi-table inheritance.',
- obj=Bar,
- id='models.E016',
- ),
- ])
+ self.assertEqual(
+ Bar.check(databases=self.databases),
+ [
+ Error(
+ "'constraints' refers to field 'field1' which is not local to "
+ "model 'Bar'.",
+ hint="This issue may be caused by multi-table inheritance.",
+ obj=Bar,
+ id="models.E016",
+ ),
+ ],
+ )
- @skipUnlessDBFeature('supports_expression_indexes')
+ @skipUnlessDBFeature("supports_expression_indexes")
def test_func_unique_constraint_pointing_to_fk(self):
class Foo(models.Model):
id = models.CharField(primary_key=True, max_length=255)
class Bar(models.Model):
- foo_1 = models.ForeignKey(Foo, models.CASCADE, related_name='bar_1')
- foo_2 = models.ForeignKey(Foo, models.CASCADE, related_name='bar_2')
+ foo_1 = models.ForeignKey(Foo, models.CASCADE, related_name="bar_1")
+ foo_2 = models.ForeignKey(Foo, models.CASCADE, related_name="bar_2")
class Meta:
constraints = [
models.UniqueConstraint(
- Lower('foo_1_id'),
- Lower('foo_2'),
- name='name',
+ Lower("foo_1_id"),
+ Lower("foo_2"),
+ name="name",
),
]
diff --git a/tests/invalid_models_tests/test_ordinary_fields.py b/tests/invalid_models_tests/test_ordinary_fields.py
index 7797b24202..ba63cb2903 100644
--- a/tests/invalid_models_tests/test_ordinary_fields.py
+++ b/tests/invalid_models_tests/test_ordinary_fields.py
@@ -1,11 +1,10 @@
import unittest
import uuid
-from django.core.checks import Error, Warning as DjangoWarning
+from django.core.checks import Error
+from django.core.checks import Warning as DjangoWarning
from django.db import connection, models
-from django.test import (
- SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature,
-)
+from django.test import SimpleTestCase, TestCase, skipIfDBFeature, skipUnlessDBFeature
from django.test.utils import isolate_apps, override_settings
from django.utils.functional import lazy
from django.utils.timezone import now
@@ -13,14 +12,13 @@ from django.utils.translation import gettext_lazy as _
from django.utils.version import get_docs_version
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class AutoFieldTests(SimpleTestCase):
-
def test_valid_case(self):
class Model(models.Model):
id = models.AutoField(primary_key=True)
- field = Model._meta.get_field('id')
+ field = Model._meta.get_field("id")
self.assertEqual(field.check(), [])
def test_primary_key(self):
@@ -33,167 +31,196 @@ class AutoFieldTests(SimpleTestCase):
# AutoField.
another = models.IntegerField(primary_key=True)
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- 'AutoFields must set primary_key=True.',
- obj=field,
- id='fields.E100',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "AutoFields must set primary_key=True.",
+ obj=field,
+ id="fields.E100",
+ ),
+ ],
+ )
def test_max_length_warning(self):
class Model(models.Model):
auto = models.AutoField(primary_key=True, max_length=2)
- field = Model._meta.get_field('auto')
- self.assertEqual(field.check(), [
- DjangoWarning(
- "'max_length' is ignored when used with %s."
- % field.__class__.__name__,
- hint="Remove 'max_length' from field",
- obj=field,
- id='fields.W122',
- ),
- ])
+ field = Model._meta.get_field("auto")
+ self.assertEqual(
+ field.check(),
+ [
+ DjangoWarning(
+ "'max_length' is ignored when used with %s."
+ % field.__class__.__name__,
+ hint="Remove 'max_length' from field",
+ obj=field,
+ id="fields.W122",
+ ),
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class BinaryFieldTests(SimpleTestCase):
-
def test_valid_default_value(self):
class Model(models.Model):
- field1 = models.BinaryField(default=b'test')
+ field1 = models.BinaryField(default=b"test")
field2 = models.BinaryField(default=None)
- for field_name in ('field1', 'field2'):
+ for field_name in ("field1", "field2"):
field = Model._meta.get_field(field_name)
self.assertEqual(field.check(), [])
def test_str_default_value(self):
class Model(models.Model):
- field = models.BinaryField(default='test')
-
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "BinaryField's default cannot be a string. Use bytes content "
- "instead.",
- obj=field,
- id='fields.E170',
- ),
- ])
+ field = models.BinaryField(default="test")
+
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "BinaryField's default cannot be a string. Use bytes content "
+ "instead.",
+ obj=field,
+ id="fields.E170",
+ ),
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class CharFieldTests(TestCase):
-
def test_valid_field(self):
class Model(models.Model):
field = models.CharField(
max_length=255,
choices=[
- ('1', 'item1'),
- ('2', 'item2'),
+ ("1", "item1"),
+ ("2", "item2"),
],
db_index=True,
)
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
self.assertEqual(field.check(), [])
def test_missing_max_length(self):
class Model(models.Model):
field = models.CharField()
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "CharFields must define a 'max_length' attribute.",
- obj=field,
- id='fields.E120',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "CharFields must define a 'max_length' attribute.",
+ obj=field,
+ id="fields.E120",
+ ),
+ ],
+ )
def test_negative_max_length(self):
class Model(models.Model):
field = models.CharField(max_length=-1)
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'max_length' must be a positive integer.",
- obj=field,
- id='fields.E121',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'max_length' must be a positive integer.",
+ obj=field,
+ id="fields.E121",
+ ),
+ ],
+ )
def test_bad_max_length_value(self):
class Model(models.Model):
field = models.CharField(max_length="bad")
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'max_length' must be a positive integer.",
- obj=field,
- id='fields.E121',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'max_length' must be a positive integer.",
+ obj=field,
+ id="fields.E121",
+ ),
+ ],
+ )
def test_str_max_length_value(self):
class Model(models.Model):
- field = models.CharField(max_length='20')
-
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'max_length' must be a positive integer.",
- obj=field,
- id='fields.E121',
- ),
- ])
+ field = models.CharField(max_length="20")
+
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'max_length' must be a positive integer.",
+ obj=field,
+ id="fields.E121",
+ ),
+ ],
+ )
def test_str_max_length_type(self):
class Model(models.Model):
field = models.CharField(max_length=True)
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'max_length' must be a positive integer.",
- obj=field,
- id='fields.E121'
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'max_length' must be a positive integer.",
+ obj=field,
+ id="fields.E121",
+ ),
+ ],
+ )
def test_non_iterable_choices(self):
class Model(models.Model):
- field = models.CharField(max_length=10, choices='bad')
-
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'choices' must be an iterable (e.g., a list or tuple).",
- obj=field,
- id='fields.E004',
- ),
- ])
+ field = models.CharField(max_length=10, choices="bad")
+
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'choices' must be an iterable (e.g., a list or tuple).",
+ obj=field,
+ id="fields.E004",
+ ),
+ ],
+ )
def test_non_iterable_choices_two_letters(self):
"""Two letters isn't a valid choice pair."""
- class Model(models.Model):
- field = models.CharField(max_length=10, choices=['ab'])
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'choices' must be an iterable containing (actual value, "
- "human readable name) tuples.",
- obj=field,
- id='fields.E005',
- ),
- ])
+ class Model(models.Model):
+ field = models.CharField(max_length=10, choices=["ab"])
+
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'choices' must be an iterable containing (actual value, "
+ "human readable name) tuples.",
+ obj=field,
+ id="fields.E005",
+ ),
+ ],
+ )
def test_iterable_of_iterable_choices(self):
class ThingItem:
@@ -214,7 +241,7 @@ class CharFieldTests(TestCase):
class ThingWithIterableChoices(models.Model):
thing = models.CharField(max_length=100, blank=True, choices=Things())
- self.assertEqual(ThingWithIterableChoices._meta.get_field('thing').check(), [])
+ self.assertEqual(ThingWithIterableChoices._meta.get_field("thing").check(), [])
def test_choices_containing_non_pairs(self):
class Model(models.Model):
@@ -225,215 +252,255 @@ class CharFieldTests(TestCase):
for model in (Model, Model2):
with self.subTest(model.__name__):
- field = model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'choices' must be an iterable containing (actual "
- "value, human readable name) tuples.",
- obj=field,
- id='fields.E005',
- ),
- ])
+ field = model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'choices' must be an iterable containing (actual "
+ "value, human readable name) tuples.",
+ obj=field,
+ id="fields.E005",
+ ),
+ ],
+ )
def test_choices_containing_lazy(self):
class Model(models.Model):
- field = models.CharField(max_length=10, choices=[['1', _('1')], ['2', _('2')]])
+ field = models.CharField(
+ max_length=10, choices=[["1", _("1")], ["2", _("2")]]
+ )
- self.assertEqual(Model._meta.get_field('field').check(), [])
+ self.assertEqual(Model._meta.get_field("field").check(), [])
def test_lazy_choices(self):
class Model(models.Model):
- field = models.CharField(max_length=10, choices=lazy(lambda: [[1, '1'], [2, '2']], tuple)())
+ field = models.CharField(
+ max_length=10, choices=lazy(lambda: [[1, "1"], [2, "2"]], tuple)()
+ )
- self.assertEqual(Model._meta.get_field('field').check(), [])
+ self.assertEqual(Model._meta.get_field("field").check(), [])
def test_choices_named_group(self):
class Model(models.Model):
field = models.CharField(
- max_length=10, choices=[
- ['knights', [['L', 'Lancelot'], ['G', 'Galahad']]],
- ['wizards', [['T', 'Tim the Enchanter']]],
- ['R', 'Random character'],
+ max_length=10,
+ choices=[
+ ["knights", [["L", "Lancelot"], ["G", "Galahad"]]],
+ ["wizards", [["T", "Tim the Enchanter"]]],
+ ["R", "Random character"],
],
)
- self.assertEqual(Model._meta.get_field('field').check(), [])
+ self.assertEqual(Model._meta.get_field("field").check(), [])
def test_choices_named_group_non_pairs(self):
class Model(models.Model):
field = models.CharField(
max_length=10,
- choices=[['knights', [['L', 'Lancelot', 'Du Lac']]]],
+ choices=[["knights", [["L", "Lancelot", "Du Lac"]]]],
)
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'choices' must be an iterable containing (actual value, "
- "human readable name) tuples.",
- obj=field,
- id='fields.E005',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'choices' must be an iterable containing (actual value, "
+ "human readable name) tuples.",
+ obj=field,
+ id="fields.E005",
+ ),
+ ],
+ )
def test_choices_named_group_bad_structure(self):
class Model(models.Model):
field = models.CharField(
- max_length=10, choices=[
- ['knights', [
- ['Noble', [['G', 'Galahad']]],
- ['Combative', [['L', 'Lancelot']]],
- ]],
+ max_length=10,
+ choices=[
+ [
+ "knights",
+ [
+ ["Noble", [["G", "Galahad"]]],
+ ["Combative", [["L", "Lancelot"]]],
+ ],
+ ],
],
)
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'choices' must be an iterable containing (actual value, "
- "human readable name) tuples.",
- obj=field,
- id='fields.E005',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'choices' must be an iterable containing (actual value, "
+ "human readable name) tuples.",
+ obj=field,
+ id="fields.E005",
+ ),
+ ],
+ )
def test_choices_named_group_lazy(self):
class Model(models.Model):
field = models.CharField(
- max_length=10, choices=[
- [_('knights'), [['L', _('Lancelot')], ['G', _('Galahad')]]],
- ['R', _('Random character')],
+ max_length=10,
+ choices=[
+ [_("knights"), [["L", _("Lancelot")], ["G", _("Galahad")]]],
+ ["R", _("Random character")],
],
)
- self.assertEqual(Model._meta.get_field('field').check(), [])
+ self.assertEqual(Model._meta.get_field("field").check(), [])
def test_choices_in_max_length(self):
class Model(models.Model):
field = models.CharField(
- max_length=2, choices=[
- ('ABC', 'Value Too Long!'), ('OK', 'Good')
- ],
+ max_length=2,
+ choices=[("ABC", "Value Too Long!"), ("OK", "Good")],
)
group = models.CharField(
- max_length=2, choices=[
- ('Nested', [('OK', 'Good'), ('Longer', 'Longer')]),
- ('Grouped', [('Bad', 'Bad')]),
+ max_length=2,
+ choices=[
+ ("Nested", [("OK", "Good"), ("Longer", "Longer")]),
+ ("Grouped", [("Bad", "Bad")]),
],
)
- for name, choice_max_length in (('field', 3), ('group', 6)):
+ for name, choice_max_length in (("field", 3), ("group", 6)):
with self.subTest(name):
field = Model._meta.get_field(name)
- self.assertEqual(field.check(), [
- Error(
- "'max_length' is too small to fit the longest value "
- "in 'choices' (%d characters)." % choice_max_length,
- obj=field,
- id='fields.E009',
- ),
- ])
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'max_length' is too small to fit the longest value "
+ "in 'choices' (%d characters)." % choice_max_length,
+ obj=field,
+ id="fields.E009",
+ ),
+ ],
+ )
def test_bad_db_index_value(self):
class Model(models.Model):
- field = models.CharField(max_length=10, db_index='bad')
-
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'db_index' must be None, True or False.",
- obj=field,
- id='fields.E006',
- ),
- ])
+ field = models.CharField(max_length=10, db_index="bad")
+
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'db_index' must be None, True or False.",
+ obj=field,
+ id="fields.E006",
+ ),
+ ],
+ )
def test_bad_validators(self):
class Model(models.Model):
field = models.CharField(max_length=10, validators=[True])
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "All 'validators' must be callable.",
- hint=(
- "validators[0] (True) isn't a function or instance of a "
- "validator class."
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "All 'validators' must be callable.",
+ hint=(
+ "validators[0] (True) isn't a function or instance of a "
+ "validator class."
+ ),
+ obj=field,
+ id="fields.E008",
),
- obj=field,
- id='fields.E008',
- ),
- ])
+ ],
+ )
- @unittest.skipUnless(connection.vendor == 'mysql',
- "Test valid only for MySQL")
+ @unittest.skipUnless(connection.vendor == "mysql", "Test valid only for MySQL")
def test_too_long_char_field_under_mysql(self):
from django.db.backends.mysql.validation import DatabaseValidation
class Model(models.Model):
field = models.CharField(unique=True, max_length=256)
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
validator = DatabaseValidation(connection=connection)
- self.assertEqual(validator.check_field(field), [
- DjangoWarning(
- '%s may not allow unique CharFields to have a max_length > '
- '255.' % connection.display_name,
- hint=(
- 'See: https://docs.djangoproject.com/en/%s/ref/databases/'
- '#mysql-character-fields' % get_docs_version()
- ),
- obj=field,
- id='mysql.W003',
- )
- ])
+ self.assertEqual(
+ validator.check_field(field),
+ [
+ DjangoWarning(
+ "%s may not allow unique CharFields to have a max_length > "
+ "255." % connection.display_name,
+ hint=(
+ "See: https://docs.djangoproject.com/en/%s/ref/databases/"
+ "#mysql-character-fields" % get_docs_version()
+ ),
+ obj=field,
+ id="mysql.W003",
+ )
+ ],
+ )
def test_db_collation(self):
class Model(models.Model):
- field = models.CharField(max_length=100, db_collation='anything')
+ field = models.CharField(max_length=100, db_collation="anything")
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
error = Error(
- '%s does not support a database collation on CharFields.'
+ "%s does not support a database collation on CharFields."
% connection.display_name,
- id='fields.E190',
+ id="fields.E190",
obj=field,
)
- expected = [] if connection.features.supports_collation_on_charfield else [error]
+ expected = (
+ [] if connection.features.supports_collation_on_charfield else [error]
+ )
self.assertEqual(field.check(databases=self.databases), expected)
def test_db_collation_required_db_features(self):
class Model(models.Model):
- field = models.CharField(max_length=100, db_collation='anything')
+ field = models.CharField(max_length=100, db_collation="anything")
class Meta:
- required_db_features = {'supports_collation_on_charfield'}
+ required_db_features = {"supports_collation_on_charfield"}
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
self.assertEqual(field.check(databases=self.databases), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class DateFieldTests(SimpleTestCase):
maxDiff = None
def test_auto_now_and_auto_now_add_raise_error(self):
class Model(models.Model):
field0 = models.DateTimeField(auto_now=True, auto_now_add=True, default=now)
- field1 = models.DateTimeField(auto_now=True, auto_now_add=False, default=now)
- field2 = models.DateTimeField(auto_now=False, auto_now_add=True, default=now)
- field3 = models.DateTimeField(auto_now=True, auto_now_add=True, default=None)
+ field1 = models.DateTimeField(
+ auto_now=True, auto_now_add=False, default=now
+ )
+ field2 = models.DateTimeField(
+ auto_now=False, auto_now_add=True, default=now
+ )
+ field3 = models.DateTimeField(
+ auto_now=True, auto_now_add=True, default=None
+ )
expected = []
checks = []
for i in range(4):
- field = Model._meta.get_field('field%d' % i)
- expected.append(Error(
- "The options auto_now, auto_now_add, and default "
- "are mutually exclusive. Only one of these options "
- "may be present.",
- obj=field,
- id='fields.E160',
- ))
+ field = Model._meta.get_field("field%d" % i)
+ expected.append(
+ Error(
+ "The options auto_now, auto_now_add, and default "
+ "are mutually exclusive. Only one of these options "
+ "may be present.",
+ obj=field,
+ id="fields.E160",
+ )
+ )
checks.extend(field.check())
self.assertEqual(checks, expected)
@@ -443,39 +510,42 @@ class DateFieldTests(SimpleTestCase):
field_d = models.DateField(default=now().date())
field_now = models.DateField(default=now)
- field_dt = Model._meta.get_field('field_dt')
- field_d = Model._meta.get_field('field_d')
- field_now = Model._meta.get_field('field_now')
+ field_dt = Model._meta.get_field("field_dt")
+ field_d = Model._meta.get_field("field_d")
+ field_now = Model._meta.get_field("field_now")
errors = field_dt.check()
errors.extend(field_d.check())
errors.extend(field_now.check()) # doesn't raise a warning
- self.assertEqual(errors, [
- DjangoWarning(
- 'Fixed default value provided.',
- hint='It seems you set a fixed date / time / datetime '
- 'value as default for this field. This may not be '
- 'what you want. If you want to have the current date '
- 'as default, use `django.utils.timezone.now`',
- obj=field_dt,
- id='fields.W161',
- ),
- DjangoWarning(
- 'Fixed default value provided.',
- hint='It seems you set a fixed date / time / datetime '
- 'value as default for this field. This may not be '
- 'what you want. If you want to have the current date '
- 'as default, use `django.utils.timezone.now`',
- obj=field_d,
- id='fields.W161',
- )
- ])
+ self.assertEqual(
+ errors,
+ [
+ DjangoWarning(
+ "Fixed default value provided.",
+ hint="It seems you set a fixed date / time / datetime "
+ "value as default for this field. This may not be "
+ "what you want. If you want to have the current date "
+ "as default, use `django.utils.timezone.now`",
+ obj=field_dt,
+ id="fields.W161",
+ ),
+ DjangoWarning(
+ "Fixed default value provided.",
+ hint="It seems you set a fixed date / time / datetime "
+ "value as default for this field. This may not be "
+ "what you want. If you want to have the current date "
+ "as default, use `django.utils.timezone.now`",
+ obj=field_d,
+ id="fields.W161",
+ ),
+ ],
+ )
@override_settings(USE_TZ=True)
def test_fix_default_value_tz(self):
self.test_fix_default_value()
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class DateTimeFieldTests(SimpleTestCase):
maxDiff = None
@@ -485,209 +555,233 @@ class DateTimeFieldTests(SimpleTestCase):
field_d = models.DateTimeField(default=now().date())
field_now = models.DateTimeField(default=now)
- field_dt = Model._meta.get_field('field_dt')
- field_d = Model._meta.get_field('field_d')
- field_now = Model._meta.get_field('field_now')
+ field_dt = Model._meta.get_field("field_dt")
+ field_d = Model._meta.get_field("field_d")
+ field_now = Model._meta.get_field("field_now")
errors = field_dt.check()
errors.extend(field_d.check())
errors.extend(field_now.check()) # doesn't raise a warning
- self.assertEqual(errors, [
- DjangoWarning(
- 'Fixed default value provided.',
- hint='It seems you set a fixed date / time / datetime '
- 'value as default for this field. This may not be '
- 'what you want. If you want to have the current date '
- 'as default, use `django.utils.timezone.now`',
- obj=field_dt,
- id='fields.W161',
- ),
- DjangoWarning(
- 'Fixed default value provided.',
- hint='It seems you set a fixed date / time / datetime '
- 'value as default for this field. This may not be '
- 'what you want. If you want to have the current date '
- 'as default, use `django.utils.timezone.now`',
- obj=field_d,
- id='fields.W161',
- )
- ])
+ self.assertEqual(
+ errors,
+ [
+ DjangoWarning(
+ "Fixed default value provided.",
+ hint="It seems you set a fixed date / time / datetime "
+ "value as default for this field. This may not be "
+ "what you want. If you want to have the current date "
+ "as default, use `django.utils.timezone.now`",
+ obj=field_dt,
+ id="fields.W161",
+ ),
+ DjangoWarning(
+ "Fixed default value provided.",
+ hint="It seems you set a fixed date / time / datetime "
+ "value as default for this field. This may not be "
+ "what you want. If you want to have the current date "
+ "as default, use `django.utils.timezone.now`",
+ obj=field_d,
+ id="fields.W161",
+ ),
+ ],
+ )
@override_settings(USE_TZ=True)
def test_fix_default_value_tz(self):
self.test_fix_default_value()
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class DecimalFieldTests(SimpleTestCase):
-
def test_required_attributes(self):
class Model(models.Model):
field = models.DecimalField()
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "DecimalFields must define a 'decimal_places' attribute.",
- obj=field,
- id='fields.E130',
- ),
- Error(
- "DecimalFields must define a 'max_digits' attribute.",
- obj=field,
- id='fields.E132',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "DecimalFields must define a 'decimal_places' attribute.",
+ obj=field,
+ id="fields.E130",
+ ),
+ Error(
+ "DecimalFields must define a 'max_digits' attribute.",
+ obj=field,
+ id="fields.E132",
+ ),
+ ],
+ )
def test_negative_max_digits_and_decimal_places(self):
class Model(models.Model):
field = models.DecimalField(max_digits=-1, decimal_places=-1)
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'decimal_places' must be a non-negative integer.",
- obj=field,
- id='fields.E131',
- ),
- Error(
- "'max_digits' must be a positive integer.",
- obj=field,
- id='fields.E133',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'decimal_places' must be a non-negative integer.",
+ obj=field,
+ id="fields.E131",
+ ),
+ Error(
+ "'max_digits' must be a positive integer.",
+ obj=field,
+ id="fields.E133",
+ ),
+ ],
+ )
def test_bad_values_of_max_digits_and_decimal_places(self):
class Model(models.Model):
field = models.DecimalField(max_digits="bad", decimal_places="bad")
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'decimal_places' must be a non-negative integer.",
- obj=field,
- id='fields.E131',
- ),
- Error(
- "'max_digits' must be a positive integer.",
- obj=field,
- id='fields.E133',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'decimal_places' must be a non-negative integer.",
+ obj=field,
+ id="fields.E131",
+ ),
+ Error(
+ "'max_digits' must be a positive integer.",
+ obj=field,
+ id="fields.E133",
+ ),
+ ],
+ )
def test_decimal_places_greater_than_max_digits(self):
class Model(models.Model):
field = models.DecimalField(max_digits=9, decimal_places=10)
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'max_digits' must be greater or equal to 'decimal_places'.",
- obj=field,
- id='fields.E134',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'max_digits' must be greater or equal to 'decimal_places'.",
+ obj=field,
+ id="fields.E134",
+ ),
+ ],
+ )
def test_valid_field(self):
class Model(models.Model):
field = models.DecimalField(max_digits=10, decimal_places=10)
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
self.assertEqual(field.check(), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class FileFieldTests(SimpleTestCase):
-
def test_valid_default_case(self):
class Model(models.Model):
field = models.FileField()
- self.assertEqual(Model._meta.get_field('field').check(), [])
+ self.assertEqual(Model._meta.get_field("field").check(), [])
def test_valid_case(self):
class Model(models.Model):
- field = models.FileField(upload_to='somewhere')
+ field = models.FileField(upload_to="somewhere")
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
self.assertEqual(field.check(), [])
def test_primary_key(self):
class Model(models.Model):
- field = models.FileField(primary_key=False, upload_to='somewhere')
-
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'primary_key' is not a valid argument for a FileField.",
- obj=field,
- id='fields.E201',
- )
- ])
+ field = models.FileField(primary_key=False, upload_to="somewhere")
+
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'primary_key' is not a valid argument for a FileField.",
+ obj=field,
+ id="fields.E201",
+ )
+ ],
+ )
def test_upload_to_starts_with_slash(self):
class Model(models.Model):
- field = models.FileField(upload_to='/somewhere')
-
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "FileField's 'upload_to' argument must be a relative path, not "
- "an absolute path.",
- obj=field,
- id='fields.E202',
- hint='Remove the leading slash.',
- )
- ])
+ field = models.FileField(upload_to="/somewhere")
+
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "FileField's 'upload_to' argument must be a relative path, not "
+ "an absolute path.",
+ obj=field,
+ id="fields.E202",
+ hint="Remove the leading slash.",
+ )
+ ],
+ )
def test_upload_to_callable_not_checked(self):
def callable(instance, filename):
- return '/' + filename
+ return "/" + filename
class Model(models.Model):
field = models.FileField(upload_to=callable)
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
self.assertEqual(field.check(), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class FilePathFieldTests(SimpleTestCase):
-
def test_forbidden_files_and_folders(self):
class Model(models.Model):
field = models.FilePathField(allow_files=False, allow_folders=False)
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "FilePathFields must have either 'allow_files' or 'allow_folders' set to True.",
- obj=field,
- id='fields.E140',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "FilePathFields must have either 'allow_files' or 'allow_folders' set to True.",
+ obj=field,
+ id="fields.E140",
+ ),
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class GenericIPAddressFieldTests(SimpleTestCase):
-
def test_non_nullable_blank(self):
class Model(models.Model):
field = models.GenericIPAddressField(null=False, blank=True)
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- ('GenericIPAddressFields cannot have blank=True if null=False, '
- 'as blank values are stored as nulls.'),
- obj=field,
- id='fields.E150',
- ),
- ])
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ (
+ "GenericIPAddressFields cannot have blank=True if null=False, "
+ "as blank values are stored as nulls."
+ ),
+ obj=field,
+ id="fields.E150",
+ ),
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class ImageFieldTests(SimpleTestCase):
-
def test_pillow_installed(self):
try:
from PIL import Image # NOQA
@@ -697,25 +791,30 @@ class ImageFieldTests(SimpleTestCase):
pillow_installed = True
class Model(models.Model):
- field = models.ImageField(upload_to='somewhere')
+ field = models.ImageField(upload_to="somewhere")
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
errors = field.check()
- expected = [] if pillow_installed else [
- Error(
- 'Cannot use ImageField because Pillow is not installed.',
- hint=('Get Pillow at https://pypi.org/project/Pillow/ '
- 'or run command "python -m pip install Pillow".'),
- obj=field,
- id='fields.E210',
- ),
- ]
+ expected = (
+ []
+ if pillow_installed
+ else [
+ Error(
+ "Cannot use ImageField because Pillow is not installed.",
+ hint=(
+ "Get Pillow at https://pypi.org/project/Pillow/ "
+ 'or run command "python -m pip install Pillow".'
+ ),
+ obj=field,
+ id="fields.E210",
+ ),
+ ]
+ )
self.assertEqual(errors, expected)
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class IntegerFieldTests(SimpleTestCase):
-
def test_max_length_warning(self):
class Model(models.Model):
integer = models.IntegerField(max_length=2)
@@ -729,17 +828,21 @@ class IntegerFieldTests(SimpleTestCase):
if field.auto_created:
continue
with self.subTest(name=field.name):
- self.assertEqual(field.check(), [
- DjangoWarning(
- "'max_length' is ignored when used with %s." % field.__class__.__name__,
- hint="Remove 'max_length' from field",
- obj=field,
- id='fields.W122',
- )
- ])
-
-
-@isolate_apps('invalid_models_tests')
+ self.assertEqual(
+ field.check(),
+ [
+ DjangoWarning(
+ "'max_length' is ignored when used with %s."
+ % field.__class__.__name__,
+ hint="Remove 'max_length' from field",
+ obj=field,
+ id="fields.W122",
+ )
+ ],
+ )
+
+
+@isolate_apps("invalid_models_tests")
class TimeFieldTests(SimpleTestCase):
maxDiff = None
@@ -751,153 +854,171 @@ class TimeFieldTests(SimpleTestCase):
field_tz = models.TimeField(default=now().timetz())
field_now = models.DateField(default=now)
- names = ['field_dt', 'field_t', 'field_tz', 'field_now']
+ names = ["field_dt", "field_t", "field_tz", "field_now"]
fields = [Model._meta.get_field(name) for name in names]
errors = []
for field in fields:
errors.extend(field.check())
- self.assertEqual(errors, [
- DjangoWarning(
- 'Fixed default value provided.',
- hint='It seems you set a fixed date / time / datetime '
- 'value as default for this field. This may not be '
- 'what you want. If you want to have the current date '
- 'as default, use `django.utils.timezone.now`',
- obj=fields[0],
- id='fields.W161',
- ),
- DjangoWarning(
- 'Fixed default value provided.',
- hint='It seems you set a fixed date / time / datetime '
- 'value as default for this field. This may not be '
- 'what you want. If you want to have the current date '
- 'as default, use `django.utils.timezone.now`',
- obj=fields[1],
- id='fields.W161',
- ),
- DjangoWarning(
- 'Fixed default value provided.',
- hint=(
- 'It seems you set a fixed date / time / datetime value as '
- 'default for this field. This may not be what you want. '
- 'If you want to have the current date as default, use '
- '`django.utils.timezone.now`'
+ self.assertEqual(
+ errors,
+ [
+ DjangoWarning(
+ "Fixed default value provided.",
+ hint="It seems you set a fixed date / time / datetime "
+ "value as default for this field. This may not be "
+ "what you want. If you want to have the current date "
+ "as default, use `django.utils.timezone.now`",
+ obj=fields[0],
+ id="fields.W161",
+ ),
+ DjangoWarning(
+ "Fixed default value provided.",
+ hint="It seems you set a fixed date / time / datetime "
+ "value as default for this field. This may not be "
+ "what you want. If you want to have the current date "
+ "as default, use `django.utils.timezone.now`",
+ obj=fields[1],
+ id="fields.W161",
),
- obj=fields[2],
- id='fields.W161',
- ),
- # field_now doesn't raise a warning.
- ])
+ DjangoWarning(
+ "Fixed default value provided.",
+ hint=(
+ "It seems you set a fixed date / time / datetime value as "
+ "default for this field. This may not be what you want. "
+ "If you want to have the current date as default, use "
+ "`django.utils.timezone.now`"
+ ),
+ obj=fields[2],
+ id="fields.W161",
+ ),
+ # field_now doesn't raise a warning.
+ ],
+ )
@override_settings(USE_TZ=True)
def test_fix_default_value_tz(self):
self.test_fix_default_value()
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class TextFieldTests(TestCase):
-
- @skipIfDBFeature('supports_index_on_text_field')
+ @skipIfDBFeature("supports_index_on_text_field")
def test_max_length_warning(self):
class Model(models.Model):
value = models.TextField(db_index=True)
- field = Model._meta.get_field('value')
+
+ field = Model._meta.get_field("value")
field_type = field.db_type(connection)
- self.assertEqual(field.check(databases=self.databases), [
- DjangoWarning(
- '%s does not support a database index on %s columns.'
- % (connection.display_name, field_type),
- hint=(
- "An index won't be created. Silence this warning if you "
- "don't care about it."
- ),
- obj=field,
- id='fields.W162',
- )
- ])
+ self.assertEqual(
+ field.check(databases=self.databases),
+ [
+ DjangoWarning(
+ "%s does not support a database index on %s columns."
+ % (connection.display_name, field_type),
+ hint=(
+ "An index won't be created. Silence this warning if you "
+ "don't care about it."
+ ),
+ obj=field,
+ id="fields.W162",
+ )
+ ],
+ )
def test_db_collation(self):
class Model(models.Model):
- field = models.TextField(db_collation='anything')
+ field = models.TextField(db_collation="anything")
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
error = Error(
- '%s does not support a database collation on TextFields.'
+ "%s does not support a database collation on TextFields."
% connection.display_name,
- id='fields.E190',
+ id="fields.E190",
obj=field,
)
- expected = [] if connection.features.supports_collation_on_textfield else [error]
+ expected = (
+ [] if connection.features.supports_collation_on_textfield else [error]
+ )
self.assertEqual(field.check(databases=self.databases), expected)
def test_db_collation_required_db_features(self):
class Model(models.Model):
- field = models.TextField(db_collation='anything')
+ field = models.TextField(db_collation="anything")
class Meta:
- required_db_features = {'supports_collation_on_textfield'}
+ required_db_features = {"supports_collation_on_textfield"}
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
self.assertEqual(field.check(databases=self.databases), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class UUIDFieldTests(TestCase):
def test_choices_named_group(self):
class Model(models.Model):
field = models.UUIDField(
choices=[
- ['knights', [
- [uuid.UUID('5c859437-d061-4847-b3f7-e6b78852f8c8'), 'Lancelot'],
- [uuid.UUID('c7853ec1-2ea3-4359-b02d-b54e8f1bcee2'), 'Galahad'],
- ]],
- [uuid.UUID('25d405be-4895-4d50-9b2e-d6695359ce47'), 'Other'],
+ [
+ "knights",
+ [
+ [
+ uuid.UUID("5c859437-d061-4847-b3f7-e6b78852f8c8"),
+ "Lancelot",
+ ],
+ [
+ uuid.UUID("c7853ec1-2ea3-4359-b02d-b54e8f1bcee2"),
+ "Galahad",
+ ],
+ ],
+ ],
+ [uuid.UUID("25d405be-4895-4d50-9b2e-d6695359ce47"), "Other"],
],
)
- self.assertEqual(Model._meta.get_field('field').check(), [])
+ self.assertEqual(Model._meta.get_field("field").check(), [])
-@isolate_apps('invalid_models_tests')
-@skipUnlessDBFeature('supports_json_field')
+@isolate_apps("invalid_models_tests")
+@skipUnlessDBFeature("supports_json_field")
class JSONFieldTests(TestCase):
def test_invalid_default(self):
class Model(models.Model):
field = models.JSONField(default={})
- self.assertEqual(Model._meta.get_field('field').check(), [
- DjangoWarning(
- msg=(
- "JSONField default should be a callable instead of an "
- "instance so that it's not shared between all field "
- "instances."
- ),
- hint=(
- 'Use a callable instead, e.g., use `dict` instead of `{}`.'
- ),
- obj=Model._meta.get_field('field'),
- id='fields.E010',
- )
- ])
+ self.assertEqual(
+ Model._meta.get_field("field").check(),
+ [
+ DjangoWarning(
+ msg=(
+ "JSONField default should be a callable instead of an "
+ "instance so that it's not shared between all field "
+ "instances."
+ ),
+ hint=("Use a callable instead, e.g., use `dict` instead of `{}`."),
+ obj=Model._meta.get_field("field"),
+ id="fields.E010",
+ )
+ ],
+ )
def test_valid_default(self):
class Model(models.Model):
field = models.JSONField(default=dict)
- self.assertEqual(Model._meta.get_field('field').check(), [])
+ self.assertEqual(Model._meta.get_field("field").check(), [])
def test_valid_default_none(self):
class Model(models.Model):
field = models.JSONField(default=None)
- self.assertEqual(Model._meta.get_field('field').check(), [])
+ self.assertEqual(Model._meta.get_field("field").check(), [])
def test_valid_callable_default(self):
def callable_default():
- return {'it': 'works'}
+ return {"it": "works"}
class Model(models.Model):
field = models.JSONField(default=callable_default)
- self.assertEqual(Model._meta.get_field('field').check(), [])
+ self.assertEqual(Model._meta.get_field("field").check(), [])
diff --git a/tests/invalid_models_tests/test_relative_fields.py b/tests/invalid_models_tests/test_relative_fields.py
index 438d1b2a45..1dc4e7e6be 100644
--- a/tests/invalid_models_tests/test_relative_fields.py
+++ b/tests/invalid_models_tests/test_relative_fields.py
@@ -1,23 +1,23 @@
from unittest import mock
-from django.core.checks import Error, Warning as DjangoWarning
+from django.core.checks import Error
+from django.core.checks import Warning as DjangoWarning
from django.db import connection, models
from django.test.testcases import SimpleTestCase
from django.test.utils import isolate_apps, modify_settings, override_settings
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class RelativeFieldTests(SimpleTestCase):
-
def test_valid_foreign_key_without_accessor(self):
class Target(models.Model):
# There would be a clash if Model.field installed an accessor.
model = models.IntegerField()
class Model(models.Model):
- field = models.ForeignKey(Target, models.CASCADE, related_name='+')
+ field = models.ForeignKey(Target, models.CASCADE, related_name="+")
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
self.assertEqual(field.check(), [])
def test_foreign_key_to_missing_model(self):
@@ -25,60 +25,68 @@ class RelativeFieldTests(SimpleTestCase):
# test relative fields in isolation and we need to attach them to a
# model.
class Model(models.Model):
- foreign_key = models.ForeignKey('Rel1', models.CASCADE)
-
- field = Model._meta.get_field('foreign_key')
- self.assertEqual(field.check(), [
- Error(
- "Field defines a relation with model 'Rel1', "
- "which is either not installed, or is abstract.",
- obj=field,
- id='fields.E300',
- ),
- ])
+ foreign_key = models.ForeignKey("Rel1", models.CASCADE)
+
+ field = Model._meta.get_field("foreign_key")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "Field defines a relation with model 'Rel1', "
+ "which is either not installed, or is abstract.",
+ obj=field,
+ id="fields.E300",
+ ),
+ ],
+ )
- @isolate_apps('invalid_models_tests')
+ @isolate_apps("invalid_models_tests")
def test_foreign_key_to_isolate_apps_model(self):
"""
#25723 - Referenced model registration lookup should be run against the
field's model registry.
"""
+
class OtherModel(models.Model):
pass
class Model(models.Model):
- foreign_key = models.ForeignKey('OtherModel', models.CASCADE)
+ foreign_key = models.ForeignKey("OtherModel", models.CASCADE)
- field = Model._meta.get_field('foreign_key')
+ field = Model._meta.get_field("foreign_key")
self.assertEqual(field.check(from_model=Model), [])
def test_many_to_many_to_missing_model(self):
class Model(models.Model):
m2m = models.ManyToManyField("Rel2")
- field = Model._meta.get_field('m2m')
- self.assertEqual(field.check(from_model=Model), [
- Error(
- "Field defines a relation with model 'Rel2', "
- "which is either not installed, or is abstract.",
- obj=field,
- id='fields.E300',
- ),
- ])
+ field = Model._meta.get_field("m2m")
+ self.assertEqual(
+ field.check(from_model=Model),
+ [
+ Error(
+ "Field defines a relation with model 'Rel2', "
+ "which is either not installed, or is abstract.",
+ obj=field,
+ id="fields.E300",
+ ),
+ ],
+ )
- @isolate_apps('invalid_models_tests')
+ @isolate_apps("invalid_models_tests")
def test_many_to_many_to_isolate_apps_model(self):
"""
#25723 - Referenced model registration lookup should be run against the
field's model registry.
"""
+
class OtherModel(models.Model):
pass
class Model(models.Model):
- m2m = models.ManyToManyField('OtherModel')
+ m2m = models.ManyToManyField("OtherModel")
- field = Model._meta.get_field('m2m')
+ field = Model._meta.get_field("m2m")
self.assertEqual(field.check(from_model=Model), [])
def test_many_to_many_with_useless_options(self):
@@ -88,93 +96,112 @@ class RelativeFieldTests(SimpleTestCase):
class ModelM2M(models.Model):
m2m = models.ManyToManyField(Model, null=True, validators=[lambda x: x])
- field = ModelM2M._meta.get_field('m2m')
- self.assertEqual(ModelM2M.check(), [
- DjangoWarning(
- 'null has no effect on ManyToManyField.',
- obj=field,
- id='fields.W340',
- ),
- DjangoWarning(
- 'ManyToManyField does not support validators.',
- obj=field,
- id='fields.W341',
- ),
- ])
+ field = ModelM2M._meta.get_field("m2m")
+ self.assertEqual(
+ ModelM2M.check(),
+ [
+ DjangoWarning(
+ "null has no effect on ManyToManyField.",
+ obj=field,
+ id="fields.W340",
+ ),
+ DjangoWarning(
+ "ManyToManyField does not support validators.",
+ obj=field,
+ id="fields.W341",
+ ),
+ ],
+ )
def test_many_to_many_with_useless_related_name(self):
class ModelM2M(models.Model):
- m2m = models.ManyToManyField('self', related_name='children')
-
- field = ModelM2M._meta.get_field('m2m')
- self.assertEqual(ModelM2M.check(), [
- DjangoWarning(
- 'related_name has no effect on ManyToManyField with '
- 'a symmetrical relationship, e.g. to "self".',
- obj=field,
- id='fields.W345',
- ),
- ])
+ m2m = models.ManyToManyField("self", related_name="children")
+
+ field = ModelM2M._meta.get_field("m2m")
+ self.assertEqual(
+ ModelM2M.check(),
+ [
+ DjangoWarning(
+ "related_name has no effect on ManyToManyField with "
+ 'a symmetrical relationship, e.g. to "self".',
+ obj=field,
+ id="fields.W345",
+ ),
+ ],
+ )
def test_ambiguous_relationship_model_from(self):
class Person(models.Model):
pass
class Group(models.Model):
- field = models.ManyToManyField('Person', through='AmbiguousRelationship')
+ field = models.ManyToManyField("Person", through="AmbiguousRelationship")
class AmbiguousRelationship(models.Model):
person = models.ForeignKey(Person, models.CASCADE)
- first_group = models.ForeignKey(Group, models.CASCADE, related_name='first')
- second_group = models.ForeignKey(Group, models.CASCADE, related_name='second')
-
- field = Group._meta.get_field('field')
- self.assertEqual(field.check(from_model=Group), [
- Error(
- "The model is used as an intermediate model by "
- "'invalid_models_tests.Group.field', but it has more than one "
- "foreign key from 'Group', which is ambiguous. You must "
- "specify which foreign key Django should use via the "
- "through_fields keyword argument.",
- hint=(
- 'If you want to create a recursive relationship, use '
- 'ManyToManyField("self", through="AmbiguousRelationship").'
+ first_group = models.ForeignKey(Group, models.CASCADE, related_name="first")
+ second_group = models.ForeignKey(
+ Group, models.CASCADE, related_name="second"
+ )
+
+ field = Group._meta.get_field("field")
+ self.assertEqual(
+ field.check(from_model=Group),
+ [
+ Error(
+ "The model is used as an intermediate model by "
+ "'invalid_models_tests.Group.field', but it has more than one "
+ "foreign key from 'Group', which is ambiguous. You must "
+ "specify which foreign key Django should use via the "
+ "through_fields keyword argument.",
+ hint=(
+ "If you want to create a recursive relationship, use "
+ 'ManyToManyField("self", through="AmbiguousRelationship").'
+ ),
+ obj=field,
+ id="fields.E334",
),
- obj=field,
- id='fields.E334',
- ),
- ])
+ ],
+ )
def test_ambiguous_relationship_model_to(self):
-
class Person(models.Model):
pass
class Group(models.Model):
- field = models.ManyToManyField('Person', through="AmbiguousRelationship", related_name='tertiary')
+ field = models.ManyToManyField(
+ "Person", through="AmbiguousRelationship", related_name="tertiary"
+ )
class AmbiguousRelationship(models.Model):
# Too much foreign keys to Person.
- first_person = models.ForeignKey(Person, models.CASCADE, related_name="first")
- second_person = models.ForeignKey(Person, models.CASCADE, related_name="second")
+ first_person = models.ForeignKey(
+ Person, models.CASCADE, related_name="first"
+ )
+ second_person = models.ForeignKey(
+ Person, models.CASCADE, related_name="second"
+ )
second_model = models.ForeignKey(Group, models.CASCADE)
- field = Group._meta.get_field('field')
- self.assertEqual(field.check(from_model=Group), [
- Error(
- "The model is used as an intermediate model by "
- "'invalid_models_tests.Group.field', but it has more than one "
- "foreign key to 'Person', which is ambiguous. You must specify "
- "which foreign key Django should use via the through_fields "
- "keyword argument.",
- hint=(
- 'If you want to create a recursive relationship, use '
- 'ManyToManyField("self", through="AmbiguousRelationship").'
+ field = Group._meta.get_field("field")
+ self.assertEqual(
+ field.check(from_model=Group),
+ [
+ Error(
+ "The model is used as an intermediate model by "
+ "'invalid_models_tests.Group.field', but it has more than one "
+ "foreign key to 'Person', which is ambiguous. You must specify "
+ "which foreign key Django should use via the through_fields "
+ "keyword argument.",
+ hint=(
+ "If you want to create a recursive relationship, use "
+ 'ManyToManyField("self", through="AmbiguousRelationship").'
+ ),
+ obj=field,
+ id="fields.E335",
),
- obj=field,
- id='fields.E335',
- ),
- ])
+ ],
+ )
def test_relationship_model_with_foreign_key_to_wrong_model(self):
class WrongModel(models.Model):
@@ -184,120 +211,144 @@ class RelativeFieldTests(SimpleTestCase):
pass
class Group(models.Model):
- members = models.ManyToManyField('Person', through="InvalidRelationship")
+ members = models.ManyToManyField("Person", through="InvalidRelationship")
class InvalidRelationship(models.Model):
person = models.ForeignKey(Person, models.CASCADE)
wrong_foreign_key = models.ForeignKey(WrongModel, models.CASCADE)
# The last foreign key should point to Group model.
- field = Group._meta.get_field('members')
- self.assertEqual(field.check(from_model=Group), [
- Error(
- "The model is used as an intermediate model by "
- "'invalid_models_tests.Group.members', but it does not "
- "have a foreign key to 'Group' or 'Person'.",
- obj=InvalidRelationship,
- id='fields.E336',
- ),
- ])
+ field = Group._meta.get_field("members")
+ self.assertEqual(
+ field.check(from_model=Group),
+ [
+ Error(
+ "The model is used as an intermediate model by "
+ "'invalid_models_tests.Group.members', but it does not "
+ "have a foreign key to 'Group' or 'Person'.",
+ obj=InvalidRelationship,
+ id="fields.E336",
+ ),
+ ],
+ )
def test_relationship_model_missing_foreign_key(self):
class Person(models.Model):
pass
class Group(models.Model):
- members = models.ManyToManyField('Person', through="InvalidRelationship")
+ members = models.ManyToManyField("Person", through="InvalidRelationship")
class InvalidRelationship(models.Model):
group = models.ForeignKey(Group, models.CASCADE)
# No foreign key to Person
- field = Group._meta.get_field('members')
- self.assertEqual(field.check(from_model=Group), [
- Error(
- "The model is used as an intermediate model by "
- "'invalid_models_tests.Group.members', but it does not have "
- "a foreign key to 'Group' or 'Person'.",
- obj=InvalidRelationship,
- id='fields.E336',
- ),
- ])
+ field = Group._meta.get_field("members")
+ self.assertEqual(
+ field.check(from_model=Group),
+ [
+ Error(
+ "The model is used as an intermediate model by "
+ "'invalid_models_tests.Group.members', but it does not have "
+ "a foreign key to 'Group' or 'Person'.",
+ obj=InvalidRelationship,
+ id="fields.E336",
+ ),
+ ],
+ )
def test_missing_relationship_model(self):
class Person(models.Model):
pass
class Group(models.Model):
- members = models.ManyToManyField('Person', through="MissingM2MModel")
-
- field = Group._meta.get_field('members')
- self.assertEqual(field.check(from_model=Group), [
- Error(
- "Field specifies a many-to-many relation through model "
- "'MissingM2MModel', which has not been installed.",
- obj=field,
- id='fields.E331',
- ),
- ])
+ members = models.ManyToManyField("Person", through="MissingM2MModel")
+
+ field = Group._meta.get_field("members")
+ self.assertEqual(
+ field.check(from_model=Group),
+ [
+ Error(
+ "Field specifies a many-to-many relation through model "
+ "'MissingM2MModel', which has not been installed.",
+ obj=field,
+ id="fields.E331",
+ ),
+ ],
+ )
def test_missing_relationship_model_on_model_check(self):
class Person(models.Model):
pass
class Group(models.Model):
- members = models.ManyToManyField('Person', through='MissingM2MModel')
-
- self.assertEqual(Group.check(), [
- Error(
- "Field specifies a many-to-many relation through model "
- "'MissingM2MModel', which has not been installed.",
- obj=Group._meta.get_field('members'),
- id='fields.E331',
- ),
- ])
+ members = models.ManyToManyField("Person", through="MissingM2MModel")
- @isolate_apps('invalid_models_tests')
+ self.assertEqual(
+ Group.check(),
+ [
+ Error(
+ "Field specifies a many-to-many relation through model "
+ "'MissingM2MModel', which has not been installed.",
+ obj=Group._meta.get_field("members"),
+ id="fields.E331",
+ ),
+ ],
+ )
+
+ @isolate_apps("invalid_models_tests")
def test_many_to_many_through_isolate_apps_model(self):
"""
#25723 - Through model registration lookup should be run against the
field's model registry.
"""
+
class GroupMember(models.Model):
- person = models.ForeignKey('Person', models.CASCADE)
- group = models.ForeignKey('Group', models.CASCADE)
+ person = models.ForeignKey("Person", models.CASCADE)
+ group = models.ForeignKey("Group", models.CASCADE)
class Person(models.Model):
pass
class Group(models.Model):
- members = models.ManyToManyField('Person', through='GroupMember')
+ members = models.ManyToManyField("Person", through="GroupMember")
- field = Group._meta.get_field('members')
+ field = Group._meta.get_field("members")
self.assertEqual(field.check(from_model=Group), [])
def test_too_many_foreign_keys_in_self_referential_model(self):
class Person(models.Model):
- friends = models.ManyToManyField('self', through="InvalidRelationship", symmetrical=False)
+ friends = models.ManyToManyField(
+ "self", through="InvalidRelationship", symmetrical=False
+ )
class InvalidRelationship(models.Model):
- first = models.ForeignKey(Person, models.CASCADE, related_name="rel_from_set_2")
- second = models.ForeignKey(Person, models.CASCADE, related_name="rel_to_set_2")
- third = models.ForeignKey(Person, models.CASCADE, related_name="too_many_by_far")
-
- field = Person._meta.get_field('friends')
- self.assertEqual(field.check(from_model=Person), [
- Error(
- "The model is used as an intermediate model by "
- "'invalid_models_tests.Person.friends', but it has more than two "
- "foreign keys to 'Person', which is ambiguous. You must specify "
- "which two foreign keys Django should use via the through_fields "
- "keyword argument.",
- hint='Use through_fields to specify which two foreign keys Django should use.',
- obj=InvalidRelationship,
- id='fields.E333',
- ),
- ])
+ first = models.ForeignKey(
+ Person, models.CASCADE, related_name="rel_from_set_2"
+ )
+ second = models.ForeignKey(
+ Person, models.CASCADE, related_name="rel_to_set_2"
+ )
+ third = models.ForeignKey(
+ Person, models.CASCADE, related_name="too_many_by_far"
+ )
+
+ field = Person._meta.get_field("friends")
+ self.assertEqual(
+ field.check(from_model=Person),
+ [
+ Error(
+ "The model is used as an intermediate model by "
+ "'invalid_models_tests.Person.friends', but it has more than two "
+ "foreign keys to 'Person', which is ambiguous. You must specify "
+ "which two foreign keys Django should use via the through_fields "
+ "keyword argument.",
+ hint="Use through_fields to specify which two foreign keys Django should use.",
+ obj=InvalidRelationship,
+ id="fields.E333",
+ ),
+ ],
+ )
def test_foreign_key_to_abstract_model(self):
class AbstractModel(models.Model):
@@ -305,17 +356,17 @@ class RelativeFieldTests(SimpleTestCase):
abstract = True
class Model(models.Model):
- rel_string_foreign_key = models.ForeignKey('AbstractModel', models.CASCADE)
+ rel_string_foreign_key = models.ForeignKey("AbstractModel", models.CASCADE)
rel_class_foreign_key = models.ForeignKey(AbstractModel, models.CASCADE)
fields = [
- Model._meta.get_field('rel_string_foreign_key'),
- Model._meta.get_field('rel_class_foreign_key'),
+ Model._meta.get_field("rel_string_foreign_key"),
+ Model._meta.get_field("rel_class_foreign_key"),
]
expected_error = Error(
"Field defines a relation with model 'AbstractModel', "
"which is either not installed, or is abstract.",
- id='fields.E300',
+ id="fields.E300",
)
for field in fields:
expected_error.obj = field
@@ -327,17 +378,17 @@ class RelativeFieldTests(SimpleTestCase):
abstract = True
class Model(models.Model):
- rel_string_m2m = models.ManyToManyField('AbstractModel')
+ rel_string_m2m = models.ManyToManyField("AbstractModel")
rel_class_m2m = models.ManyToManyField(AbstractModel)
fields = [
- Model._meta.get_field('rel_string_m2m'),
- Model._meta.get_field('rel_class_m2m'),
+ Model._meta.get_field("rel_string_m2m"),
+ Model._meta.get_field("rel_class_m2m"),
]
expected_error = Error(
"Field defines a relation with model 'AbstractModel', "
"which is either not installed, or is abstract.",
- id='fields.E300',
+ id="fields.E300",
)
for field in fields:
expected_error.obj = field
@@ -348,56 +399,65 @@ class RelativeFieldTests(SimpleTestCase):
name = models.CharField(max_length=5)
class Group(models.Model):
- members = models.ManyToManyField('Person', unique=True)
-
- field = Group._meta.get_field('members')
- self.assertEqual(field.check(from_model=Group), [
- Error(
- 'ManyToManyFields cannot be unique.',
- obj=field,
- id='fields.E330',
- ),
- ])
+ members = models.ManyToManyField("Person", unique=True)
+
+ field = Group._meta.get_field("members")
+ self.assertEqual(
+ field.check(from_model=Group),
+ [
+ Error(
+ "ManyToManyFields cannot be unique.",
+ obj=field,
+ id="fields.E330",
+ ),
+ ],
+ )
def test_foreign_key_to_non_unique_field(self):
class Target(models.Model):
bad = models.IntegerField() # No unique=True
class Model(models.Model):
- foreign_key = models.ForeignKey('Target', models.CASCADE, to_field='bad')
-
- field = Model._meta.get_field('foreign_key')
- self.assertEqual(field.check(), [
- Error(
- "'Target.bad' must be unique because it is referenced by a foreign key.",
- hint=(
- 'Add unique=True to this field or add a UniqueConstraint '
- '(without condition) in the model Meta.constraints.'
+ foreign_key = models.ForeignKey("Target", models.CASCADE, to_field="bad")
+
+ field = Model._meta.get_field("foreign_key")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'Target.bad' must be unique because it is referenced by a foreign key.",
+ hint=(
+ "Add unique=True to this field or add a UniqueConstraint "
+ "(without condition) in the model Meta.constraints."
+ ),
+ obj=field,
+ id="fields.E311",
),
- obj=field,
- id='fields.E311',
- ),
- ])
+ ],
+ )
def test_foreign_key_to_non_unique_field_under_explicit_model(self):
class Target(models.Model):
bad = models.IntegerField()
class Model(models.Model):
- field = models.ForeignKey(Target, models.CASCADE, to_field='bad')
-
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'Target.bad' must be unique because it is referenced by a foreign key.",
- hint=(
- 'Add unique=True to this field or add a UniqueConstraint '
- '(without condition) in the model Meta.constraints.'
+ field = models.ForeignKey(Target, models.CASCADE, to_field="bad")
+
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'Target.bad' must be unique because it is referenced by a foreign key.",
+ hint=(
+ "Add unique=True to this field or add a UniqueConstraint "
+ "(without condition) in the model Meta.constraints."
+ ),
+ obj=field,
+ id="fields.E311",
),
- obj=field,
- id='fields.E311',
- ),
- ])
+ ],
+ )
def test_foreign_key_to_partially_unique_field(self):
class Target(models.Model):
@@ -406,28 +466,31 @@ class RelativeFieldTests(SimpleTestCase):
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['source'],
- name='tfktpuf_partial_unique',
+ fields=["source"],
+ name="tfktpuf_partial_unique",
condition=models.Q(pk__gt=2),
),
]
class Model(models.Model):
- field = models.ForeignKey(Target, models.CASCADE, to_field='source')
-
- field = Model._meta.get_field('field')
- self.assertEqual(field.check(), [
- Error(
- "'Target.source' must be unique because it is referenced by a "
- "foreign key.",
- hint=(
- 'Add unique=True to this field or add a UniqueConstraint '
- '(without condition) in the model Meta.constraints.'
+ field = models.ForeignKey(Target, models.CASCADE, to_field="source")
+
+ field = Model._meta.get_field("field")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "'Target.source' must be unique because it is referenced by a "
+ "foreign key.",
+ hint=(
+ "Add unique=True to this field or add a UniqueConstraint "
+ "(without condition) in the model Meta.constraints."
+ ),
+ obj=field,
+ id="fields.E311",
),
- obj=field,
- id='fields.E311',
- ),
- ])
+ ],
+ )
def test_foreign_key_to_unique_field_with_meta_constraint(self):
class Target(models.Model):
@@ -436,15 +499,15 @@ class RelativeFieldTests(SimpleTestCase):
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['source'],
- name='tfktufwmc_unique',
+ fields=["source"],
+ name="tfktufwmc_unique",
),
]
class Model(models.Model):
- field = models.ForeignKey(Target, models.CASCADE, to_field='source')
+ field = models.ForeignKey(Target, models.CASCADE, to_field="source")
- field = Model._meta.get_field('field')
+ field = Model._meta.get_field("field")
self.assertEqual(field.check(), [])
def test_foreign_object_to_non_unique_fields(self):
@@ -460,24 +523,27 @@ class RelativeFieldTests(SimpleTestCase):
person = models.ForeignObject(
Person,
on_delete=models.CASCADE,
- from_fields=['person_country_id', 'person_city_id'],
- to_fields=['country_id', 'city_id'],
+ from_fields=["person_country_id", "person_city_id"],
+ to_fields=["country_id", "city_id"],
)
- field = MMembership._meta.get_field('person')
- self.assertEqual(field.check(), [
- Error(
- "No subset of the fields 'country_id', 'city_id' on model 'Person' is unique.",
- hint=(
- 'Mark a single field as unique=True or add a set of '
- 'fields to a unique constraint (via unique_together or a '
- 'UniqueConstraint (without condition) in the model '
- 'Meta.constraints).'
- ),
- obj=field,
- id='fields.E310',
- )
- ])
+ field = MMembership._meta.get_field("person")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "No subset of the fields 'country_id', 'city_id' on model 'Person' is unique.",
+ hint=(
+ "Mark a single field as unique=True or add a set of "
+ "fields to a unique constraint (via unique_together or a "
+ "UniqueConstraint (without condition) in the model "
+ "Meta.constraints)."
+ ),
+ obj=field,
+ id="fields.E310",
+ )
+ ],
+ )
def test_foreign_object_to_partially_unique_field(self):
class Person(models.Model):
@@ -487,8 +553,8 @@ class RelativeFieldTests(SimpleTestCase):
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['country_id', 'city_id'],
- name='tfotpuf_partial_unique',
+ fields=["country_id", "city_id"],
+ name="tfotpuf_partial_unique",
condition=models.Q(pk__gt=2),
),
]
@@ -499,25 +565,28 @@ class RelativeFieldTests(SimpleTestCase):
person = models.ForeignObject(
Person,
on_delete=models.CASCADE,
- from_fields=['person_country_id', 'person_city_id'],
- to_fields=['country_id', 'city_id'],
+ from_fields=["person_country_id", "person_city_id"],
+ to_fields=["country_id", "city_id"],
)
- field = MMembership._meta.get_field('person')
- self.assertEqual(field.check(), [
- Error(
- "No subset of the fields 'country_id', 'city_id' on model "
- "'Person' is unique.",
- hint=(
- 'Mark a single field as unique=True or add a set of '
- 'fields to a unique constraint (via unique_together or a '
- 'UniqueConstraint (without condition) in the model '
- 'Meta.constraints).'
+ field = MMembership._meta.get_field("person")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "No subset of the fields 'country_id', 'city_id' on model "
+ "'Person' is unique.",
+ hint=(
+ "Mark a single field as unique=True or add a set of "
+ "fields to a unique constraint (via unique_together or a "
+ "UniqueConstraint (without condition) in the model "
+ "Meta.constraints)."
+ ),
+ obj=field,
+ id="fields.E310",
),
- obj=field,
- id='fields.E310',
- ),
- ])
+ ],
+ )
def test_foreign_object_to_unique_field_with_meta_constraint(self):
class Person(models.Model):
@@ -527,8 +596,8 @@ class RelativeFieldTests(SimpleTestCase):
class Meta:
constraints = [
models.UniqueConstraint(
- fields=['country_id', 'city_id'],
- name='tfotpuf_unique',
+ fields=["country_id", "city_id"],
+ name="tfotpuf_unique",
),
]
@@ -538,11 +607,11 @@ class RelativeFieldTests(SimpleTestCase):
person = models.ForeignObject(
Person,
on_delete=models.CASCADE,
- from_fields=['person_country_id', 'person_city_id'],
- to_fields=['country_id', 'city_id'],
+ from_fields=["person_country_id", "person_city_id"],
+ to_fields=["country_id", "city_id"],
)
- field = MMembership._meta.get_field('person')
+ field = MMembership._meta.get_field("person")
self.assertEqual(field.check(), [])
def test_on_delete_set_null_on_non_nullable_field(self):
@@ -550,125 +619,142 @@ class RelativeFieldTests(SimpleTestCase):
pass
class Model(models.Model):
- foreign_key = models.ForeignKey('Person', models.SET_NULL)
-
- field = Model._meta.get_field('foreign_key')
- self.assertEqual(field.check(), [
- Error(
- 'Field specifies on_delete=SET_NULL, but cannot be null.',
- hint='Set null=True argument on the field, or change the on_delete rule.',
- obj=field,
- id='fields.E320',
- ),
- ])
+ foreign_key = models.ForeignKey("Person", models.SET_NULL)
+
+ field = Model._meta.get_field("foreign_key")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "Field specifies on_delete=SET_NULL, but cannot be null.",
+ hint="Set null=True argument on the field, or change the on_delete rule.",
+ obj=field,
+ id="fields.E320",
+ ),
+ ],
+ )
def test_on_delete_set_default_without_default_value(self):
class Person(models.Model):
pass
class Model(models.Model):
- foreign_key = models.ForeignKey('Person', models.SET_DEFAULT)
-
- field = Model._meta.get_field('foreign_key')
- self.assertEqual(field.check(), [
- Error(
- 'Field specifies on_delete=SET_DEFAULT, but has no default value.',
- hint='Set a default value, or change the on_delete rule.',
- obj=field,
- id='fields.E321',
- ),
- ])
+ foreign_key = models.ForeignKey("Person", models.SET_DEFAULT)
+
+ field = Model._meta.get_field("foreign_key")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "Field specifies on_delete=SET_DEFAULT, but has no default value.",
+ hint="Set a default value, or change the on_delete rule.",
+ obj=field,
+ id="fields.E321",
+ ),
+ ],
+ )
def test_nullable_primary_key(self):
class Model(models.Model):
field = models.IntegerField(primary_key=True, null=True)
- field = Model._meta.get_field('field')
- with mock.patch.object(connection.features, 'interprets_empty_strings_as_nulls', False):
+ field = Model._meta.get_field("field")
+ with mock.patch.object(
+ connection.features, "interprets_empty_strings_as_nulls", False
+ ):
results = field.check()
- self.assertEqual(results, [
- Error(
- 'Primary keys must not have null=True.',
- hint='Set null=False on the field, or remove primary_key=True argument.',
- obj=field,
- id='fields.E007',
- ),
- ])
+ self.assertEqual(
+ results,
+ [
+ Error(
+ "Primary keys must not have null=True.",
+ hint="Set null=False on the field, or remove primary_key=True argument.",
+ obj=field,
+ id="fields.E007",
+ ),
+ ],
+ )
def test_not_swapped_model(self):
class SwappableModel(models.Model):
# A model that can be, but isn't swapped out. References to this
# model should *not* raise any validation error.
class Meta:
- swappable = 'TEST_SWAPPABLE_MODEL'
+ swappable = "TEST_SWAPPABLE_MODEL"
class Model(models.Model):
explicit_fk = models.ForeignKey(
SwappableModel,
models.CASCADE,
- related_name='explicit_fk',
+ related_name="explicit_fk",
)
implicit_fk = models.ForeignKey(
- 'invalid_models_tests.SwappableModel',
+ "invalid_models_tests.SwappableModel",
models.CASCADE,
- related_name='implicit_fk',
+ related_name="implicit_fk",
+ )
+ explicit_m2m = models.ManyToManyField(
+ SwappableModel, related_name="explicit_m2m"
)
- explicit_m2m = models.ManyToManyField(SwappableModel, related_name='explicit_m2m')
implicit_m2m = models.ManyToManyField(
- 'invalid_models_tests.SwappableModel',
- related_name='implicit_m2m',
+ "invalid_models_tests.SwappableModel",
+ related_name="implicit_m2m",
)
- explicit_fk = Model._meta.get_field('explicit_fk')
+ explicit_fk = Model._meta.get_field("explicit_fk")
self.assertEqual(explicit_fk.check(), [])
- implicit_fk = Model._meta.get_field('implicit_fk')
+ implicit_fk = Model._meta.get_field("implicit_fk")
self.assertEqual(implicit_fk.check(), [])
- explicit_m2m = Model._meta.get_field('explicit_m2m')
+ explicit_m2m = Model._meta.get_field("explicit_m2m")
self.assertEqual(explicit_m2m.check(from_model=Model), [])
- implicit_m2m = Model._meta.get_field('implicit_m2m')
+ implicit_m2m = Model._meta.get_field("implicit_m2m")
self.assertEqual(implicit_m2m.check(from_model=Model), [])
- @override_settings(TEST_SWAPPED_MODEL='invalid_models_tests.Replacement')
+ @override_settings(TEST_SWAPPED_MODEL="invalid_models_tests.Replacement")
def test_referencing_to_swapped_model(self):
class Replacement(models.Model):
pass
class SwappedModel(models.Model):
class Meta:
- swappable = 'TEST_SWAPPED_MODEL'
+ swappable = "TEST_SWAPPED_MODEL"
class Model(models.Model):
explicit_fk = models.ForeignKey(
SwappedModel,
models.CASCADE,
- related_name='explicit_fk',
+ related_name="explicit_fk",
)
implicit_fk = models.ForeignKey(
- 'invalid_models_tests.SwappedModel',
+ "invalid_models_tests.SwappedModel",
models.CASCADE,
- related_name='implicit_fk',
+ related_name="implicit_fk",
+ )
+ explicit_m2m = models.ManyToManyField(
+ SwappedModel, related_name="explicit_m2m"
)
- explicit_m2m = models.ManyToManyField(SwappedModel, related_name='explicit_m2m')
implicit_m2m = models.ManyToManyField(
- 'invalid_models_tests.SwappedModel',
- related_name='implicit_m2m',
+ "invalid_models_tests.SwappedModel",
+ related_name="implicit_m2m",
)
fields = [
- Model._meta.get_field('explicit_fk'),
- Model._meta.get_field('implicit_fk'),
- Model._meta.get_field('explicit_m2m'),
- Model._meta.get_field('implicit_m2m'),
+ Model._meta.get_field("explicit_fk"),
+ Model._meta.get_field("implicit_fk"),
+ Model._meta.get_field("explicit_m2m"),
+ Model._meta.get_field("implicit_m2m"),
]
expected_error = Error(
- ("Field defines a relation with the model "
- "'invalid_models_tests.SwappedModel', which has been swapped out."),
+ (
+ "Field defines a relation with the model "
+ "'invalid_models_tests.SwappedModel', which has been swapped out."
+ ),
hint="Update the relation to point at 'settings.TEST_SWAPPED_MODEL'.",
- id='fields.E301',
+ id="fields.E301",
)
for field in fields:
@@ -677,68 +763,83 @@ class RelativeFieldTests(SimpleTestCase):
def test_related_field_has_invalid_related_name(self):
digit = 0
- illegal_non_alphanumeric = '!'
- whitespace = '\t'
+ illegal_non_alphanumeric = "!"
+ whitespace = "\t"
invalid_related_names = [
- '%s_begins_with_digit' % digit,
- '%s_begins_with_illegal_non_alphanumeric' % illegal_non_alphanumeric,
- '%s_begins_with_whitespace' % whitespace,
- 'contains_%s_illegal_non_alphanumeric' % illegal_non_alphanumeric,
- 'contains_%s_whitespace' % whitespace,
- 'ends_with_with_illegal_non_alphanumeric_%s' % illegal_non_alphanumeric,
- 'ends_with_whitespace_%s' % whitespace,
- 'with', # a Python keyword
- 'related_name\n',
- '',
- ',', # non-ASCII
+ "%s_begins_with_digit" % digit,
+ "%s_begins_with_illegal_non_alphanumeric" % illegal_non_alphanumeric,
+ "%s_begins_with_whitespace" % whitespace,
+ "contains_%s_illegal_non_alphanumeric" % illegal_non_alphanumeric,
+ "contains_%s_whitespace" % whitespace,
+ "ends_with_with_illegal_non_alphanumeric_%s" % illegal_non_alphanumeric,
+ "ends_with_whitespace_%s" % whitespace,
+ "with", # a Python keyword
+ "related_name\n",
+ "",
+ ",", # non-ASCII
]
class Parent(models.Model):
pass
for invalid_related_name in invalid_related_names:
- Child = type('Child%s' % invalid_related_name, (models.Model,), {
- 'parent': models.ForeignKey('Parent', models.CASCADE, related_name=invalid_related_name),
- '__module__': Parent.__module__,
- })
+ Child = type(
+ "Child%s" % invalid_related_name,
+ (models.Model,),
+ {
+ "parent": models.ForeignKey(
+ "Parent", models.CASCADE, related_name=invalid_related_name
+ ),
+ "__module__": Parent.__module__,
+ },
+ )
- field = Child._meta.get_field('parent')
- self.assertEqual(Child.check(), [
- Error(
- "The name '%s' is invalid related_name for field Child%s.parent"
- % (invalid_related_name, invalid_related_name),
- hint="Related name must be a valid Python identifier or end with a '+'",
- obj=field,
- id='fields.E306',
- ),
- ])
+ field = Child._meta.get_field("parent")
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "The name '%s' is invalid related_name for field Child%s.parent"
+ % (invalid_related_name, invalid_related_name),
+ hint="Related name must be a valid Python identifier or end with a '+'",
+ obj=field,
+ id="fields.E306",
+ ),
+ ],
+ )
def test_related_field_has_valid_related_name(self):
- lowercase = 'a'
- uppercase = 'A'
+ lowercase = "a"
+ uppercase = "A"
digit = 0
related_names = [
- '%s_starts_with_lowercase' % lowercase,
- '%s_tarts_with_uppercase' % uppercase,
- '_starts_with_underscore',
- 'contains_%s_digit' % digit,
- 'ends_with_plus+',
- '_+',
- '+',
- '試',
- '試驗+',
+ "%s_starts_with_lowercase" % lowercase,
+ "%s_tarts_with_uppercase" % uppercase,
+ "_starts_with_underscore",
+ "contains_%s_digit" % digit,
+ "ends_with_plus+",
+ "_+",
+ "+",
+ "試",
+ "試驗+",
]
class Parent(models.Model):
pass
for related_name in related_names:
- Child = type('Child%s' % related_name, (models.Model,), {
- 'parent': models.ForeignKey('Parent', models.CASCADE, related_name=related_name),
- '__module__': Parent.__module__,
- })
+ Child = type(
+ "Child%s" % related_name,
+ (models.Model,),
+ {
+ "parent": models.ForeignKey(
+ "Parent", models.CASCADE, related_name=related_name
+ ),
+ "__module__": Parent.__module__,
+ },
+ )
self.assertEqual(Child.check(), [])
def test_to_fields_exist(self):
@@ -751,104 +852,125 @@ class RelativeFieldTests(SimpleTestCase):
parent = models.ForeignObject(
Parent,
on_delete=models.SET_NULL,
- from_fields=('a', 'b'),
- to_fields=('a', 'b'),
+ from_fields=("a", "b"),
+ to_fields=("a", "b"),
)
- field = Child._meta.get_field('parent')
- self.assertEqual(field.check(), [
- Error(
- "The to_field 'a' doesn't exist on the related model 'invalid_models_tests.Parent'.",
- obj=field,
- id='fields.E312',
- ),
- Error(
- "The to_field 'b' doesn't exist on the related model 'invalid_models_tests.Parent'.",
- obj=field,
- id='fields.E312',
- ),
- ])
+ field = Child._meta.get_field("parent")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "The to_field 'a' doesn't exist on the related model 'invalid_models_tests.Parent'.",
+ obj=field,
+ id="fields.E312",
+ ),
+ Error(
+ "The to_field 'b' doesn't exist on the related model 'invalid_models_tests.Parent'.",
+ obj=field,
+ id="fields.E312",
+ ),
+ ],
+ )
def test_to_fields_not_checked_if_related_model_doesnt_exist(self):
class Child(models.Model):
a = models.PositiveIntegerField()
b = models.PositiveIntegerField()
parent = models.ForeignObject(
- 'invalid_models_tests.Parent',
+ "invalid_models_tests.Parent",
on_delete=models.SET_NULL,
- from_fields=('a', 'b'),
- to_fields=('a', 'b'),
+ from_fields=("a", "b"),
+ to_fields=("a", "b"),
)
- field = Child._meta.get_field('parent')
- self.assertEqual(field.check(), [
- Error(
- "Field defines a relation with model 'invalid_models_tests.Parent', "
- "which is either not installed, or is abstract.",
- id='fields.E300',
- obj=field,
- ),
- ])
+ field = Child._meta.get_field("parent")
+ self.assertEqual(
+ field.check(),
+ [
+ Error(
+ "Field defines a relation with model 'invalid_models_tests.Parent', "
+ "which is either not installed, or is abstract.",
+ id="fields.E300",
+ obj=field,
+ ),
+ ],
+ )
def test_invalid_related_query_name(self):
class Target(models.Model):
pass
class Model(models.Model):
- first = models.ForeignKey(Target, models.CASCADE, related_name='contains__double')
- second = models.ForeignKey(Target, models.CASCADE, related_query_name='ends_underscore_')
-
- self.assertEqual(Model.check(), [
- Error(
- "Reverse query name 'contains__double' must not contain '__'.",
- hint=("Add or change a related_name or related_query_name "
- "argument for this field."),
- obj=Model._meta.get_field('first'),
- id='fields.E309',
- ),
- Error(
- "Reverse query name 'ends_underscore_' must not end with an "
- "underscore.",
- hint=("Add or change a related_name or related_query_name "
- "argument for this field."),
- obj=Model._meta.get_field('second'),
- id='fields.E308',
- ),
- ])
+ first = models.ForeignKey(
+ Target, models.CASCADE, related_name="contains__double"
+ )
+ second = models.ForeignKey(
+ Target, models.CASCADE, related_query_name="ends_underscore_"
+ )
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse query name 'contains__double' must not contain '__'.",
+ hint=(
+ "Add or change a related_name or related_query_name "
+ "argument for this field."
+ ),
+ obj=Model._meta.get_field("first"),
+ id="fields.E309",
+ ),
+ Error(
+ "Reverse query name 'ends_underscore_' must not end with an "
+ "underscore.",
+ hint=(
+ "Add or change a related_name or related_query_name "
+ "argument for this field."
+ ),
+ obj=Model._meta.get_field("second"),
+ id="fields.E308",
+ ),
+ ],
+ )
-@isolate_apps('invalid_models_tests')
-class AccessorClashTests(SimpleTestCase):
+@isolate_apps("invalid_models_tests")
+class AccessorClashTests(SimpleTestCase):
def test_fk_to_integer(self):
self._test_accessor_clash(
target=models.IntegerField(),
- relative=models.ForeignKey('Target', models.CASCADE))
+ relative=models.ForeignKey("Target", models.CASCADE),
+ )
def test_fk_to_fk(self):
self._test_accessor_clash(
- target=models.ForeignKey('Another', models.CASCADE),
- relative=models.ForeignKey('Target', models.CASCADE))
+ target=models.ForeignKey("Another", models.CASCADE),
+ relative=models.ForeignKey("Target", models.CASCADE),
+ )
def test_fk_to_m2m(self):
self._test_accessor_clash(
- target=models.ManyToManyField('Another'),
- relative=models.ForeignKey('Target', models.CASCADE))
+ target=models.ManyToManyField("Another"),
+ relative=models.ForeignKey("Target", models.CASCADE),
+ )
def test_m2m_to_integer(self):
self._test_accessor_clash(
- target=models.IntegerField(),
- relative=models.ManyToManyField('Target'))
+ target=models.IntegerField(), relative=models.ManyToManyField("Target")
+ )
def test_m2m_to_fk(self):
self._test_accessor_clash(
- target=models.ForeignKey('Another', models.CASCADE),
- relative=models.ManyToManyField('Target'))
+ target=models.ForeignKey("Another", models.CASCADE),
+ relative=models.ManyToManyField("Target"),
+ )
def test_m2m_to_m2m(self):
self._test_accessor_clash(
- target=models.ManyToManyField('Another'),
- relative=models.ManyToManyField('Target'))
+ target=models.ManyToManyField("Another"),
+ relative=models.ManyToManyField("Target"),
+ )
def _test_accessor_clash(self, target, relative):
class Another(models.Model):
@@ -860,20 +982,23 @@ class AccessorClashTests(SimpleTestCase):
class Model(models.Model):
rel = relative
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Target.model_set' for "
- "'invalid_models_tests.Model.rel' clashes with field name "
- "'invalid_models_tests.Target.model_set'.",
- hint=(
- "Rename field 'invalid_models_tests.Target.model_set', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.rel'."
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Target.model_set' for "
+ "'invalid_models_tests.Model.rel' clashes with field name "
+ "'invalid_models_tests.Target.model_set'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Target.model_set', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.rel'."
+ ),
+ obj=Model._meta.get_field("rel"),
+ id="fields.E302",
),
- obj=Model._meta.get_field('rel'),
- id='fields.E302',
- ),
- ])
+ ],
+ )
def test_clash_between_accessors(self):
class Target(models.Model):
@@ -883,111 +1008,123 @@ class AccessorClashTests(SimpleTestCase):
foreign = models.ForeignKey(Target, models.CASCADE)
m2m = models.ManyToManyField(Target)
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Target.model_set' for "
- "'invalid_models_tests.Model.foreign' clashes with reverse "
- "accessor for 'invalid_models_tests.Model.m2m'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.foreign' or "
- "'invalid_models_tests.Model.m2m'."
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Target.model_set' for "
+ "'invalid_models_tests.Model.foreign' clashes with reverse "
+ "accessor for 'invalid_models_tests.Model.m2m'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.foreign' or "
+ "'invalid_models_tests.Model.m2m'."
+ ),
+ obj=Model._meta.get_field("foreign"),
+ id="fields.E304",
),
- obj=Model._meta.get_field('foreign'),
- id='fields.E304',
- ),
- Error(
- "Reverse accessor 'Target.model_set' for "
- "'invalid_models_tests.Model.m2m' clashes with reverse "
- "accessor for 'invalid_models_tests.Model.foreign'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.m2m' or "
- "'invalid_models_tests.Model.foreign'."
+ Error(
+ "Reverse accessor 'Target.model_set' for "
+ "'invalid_models_tests.Model.m2m' clashes with reverse "
+ "accessor for 'invalid_models_tests.Model.foreign'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.m2m' or "
+ "'invalid_models_tests.Model.foreign'."
+ ),
+ obj=Model._meta.get_field("m2m"),
+ id="fields.E304",
),
- obj=Model._meta.get_field('m2m'),
- id='fields.E304',
- ),
- ])
+ ],
+ )
def test_m2m_to_m2m_with_inheritance(self):
- """ Ref #22047. """
+ """Ref #22047."""
class Target(models.Model):
pass
class Model(models.Model):
- children = models.ManyToManyField('Child', related_name="m2m_clash", related_query_name="no_clash")
+ children = models.ManyToManyField(
+ "Child", related_name="m2m_clash", related_query_name="no_clash"
+ )
class Parent(models.Model):
- m2m_clash = models.ManyToManyField('Target')
+ m2m_clash = models.ManyToManyField("Target")
class Child(Parent):
pass
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Child.m2m_clash' for "
- "'invalid_models_tests.Model.children' clashes with field "
- "name 'invalid_models_tests.Child.m2m_clash'.",
- hint=(
- "Rename field 'invalid_models_tests.Child.m2m_clash', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.children'."
- ),
- obj=Model._meta.get_field('children'),
- id='fields.E302',
- )
- ])
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Child.m2m_clash' for "
+ "'invalid_models_tests.Model.children' clashes with field "
+ "name 'invalid_models_tests.Child.m2m_clash'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Child.m2m_clash', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.children'."
+ ),
+ obj=Model._meta.get_field("children"),
+ id="fields.E302",
+ )
+ ],
+ )
def test_no_clash_for_hidden_related_name(self):
class Stub(models.Model):
pass
class ManyToManyRel(models.Model):
- thing1 = models.ManyToManyField(Stub, related_name='+')
- thing2 = models.ManyToManyField(Stub, related_name='+')
+ thing1 = models.ManyToManyField(Stub, related_name="+")
+ thing2 = models.ManyToManyField(Stub, related_name="+")
class FKRel(models.Model):
- thing1 = models.ForeignKey(Stub, models.CASCADE, related_name='+')
- thing2 = models.ForeignKey(Stub, models.CASCADE, related_name='+')
+ thing1 = models.ForeignKey(Stub, models.CASCADE, related_name="+")
+ thing2 = models.ForeignKey(Stub, models.CASCADE, related_name="+")
self.assertEqual(ManyToManyRel.check(), [])
self.assertEqual(FKRel.check(), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class ReverseQueryNameClashTests(SimpleTestCase):
-
def test_fk_to_integer(self):
self._test_reverse_query_name_clash(
target=models.IntegerField(),
- relative=models.ForeignKey('Target', models.CASCADE))
+ relative=models.ForeignKey("Target", models.CASCADE),
+ )
def test_fk_to_fk(self):
self._test_reverse_query_name_clash(
- target=models.ForeignKey('Another', models.CASCADE),
- relative=models.ForeignKey('Target', models.CASCADE))
+ target=models.ForeignKey("Another", models.CASCADE),
+ relative=models.ForeignKey("Target", models.CASCADE),
+ )
def test_fk_to_m2m(self):
self._test_reverse_query_name_clash(
- target=models.ManyToManyField('Another'),
- relative=models.ForeignKey('Target', models.CASCADE))
+ target=models.ManyToManyField("Another"),
+ relative=models.ForeignKey("Target", models.CASCADE),
+ )
def test_m2m_to_integer(self):
self._test_reverse_query_name_clash(
- target=models.IntegerField(),
- relative=models.ManyToManyField('Target'))
+ target=models.IntegerField(), relative=models.ManyToManyField("Target")
+ )
def test_m2m_to_fk(self):
self._test_reverse_query_name_clash(
- target=models.ForeignKey('Another', models.CASCADE),
- relative=models.ManyToManyField('Target'))
+ target=models.ForeignKey("Another", models.CASCADE),
+ relative=models.ManyToManyField("Target"),
+ )
def test_m2m_to_m2m(self):
self._test_reverse_query_name_clash(
- target=models.ManyToManyField('Another'),
- relative=models.ManyToManyField('Target'))
+ target=models.ManyToManyField("Another"),
+ relative=models.ManyToManyField("Target"),
+ )
def _test_reverse_query_name_clash(self, target, relative):
class Another(models.Model):
@@ -999,40 +1136,43 @@ class ReverseQueryNameClashTests(SimpleTestCase):
class Model(models.Model):
rel = relative
- self.assertEqual(Model.check(), [
- Error(
- "Reverse query name for 'invalid_models_tests.Model.rel' "
- "clashes with field name 'invalid_models_tests.Target.model'.",
- hint=(
- "Rename field 'invalid_models_tests.Target.model', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.rel'."
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.rel' "
+ "clashes with field name 'invalid_models_tests.Target.model'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Target.model', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.rel'."
+ ),
+ obj=Model._meta.get_field("rel"),
+ id="fields.E303",
),
- obj=Model._meta.get_field('rel'),
- id='fields.E303',
- ),
- ])
+ ],
+ )
- @modify_settings(INSTALLED_APPS={'append': 'basic'})
- @isolate_apps('basic', 'invalid_models_tests')
+ @modify_settings(INSTALLED_APPS={"append": "basic"})
+ @isolate_apps("basic", "invalid_models_tests")
def test_no_clash_across_apps_without_accessor(self):
class Target(models.Model):
class Meta:
- app_label = 'invalid_models_tests'
+ app_label = "invalid_models_tests"
class Model(models.Model):
- m2m = models.ManyToManyField(Target, related_name='+')
+ m2m = models.ManyToManyField(Target, related_name="+")
class Meta:
- app_label = 'basic'
+ app_label = "basic"
def _test():
# Define model with the same name.
class Model(models.Model):
- m2m = models.ManyToManyField(Target, related_name='+')
+ m2m = models.ManyToManyField(Target, related_name="+")
class Meta:
- app_label = 'invalid_models_tests'
+ app_label = "invalid_models_tests"
self.assertEqual(Model.check(), [])
@@ -1040,38 +1180,43 @@ class ReverseQueryNameClashTests(SimpleTestCase):
self.assertEqual(Model.check(), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class ExplicitRelatedNameClashTests(SimpleTestCase):
-
def test_fk_to_integer(self):
self._test_explicit_related_name_clash(
target=models.IntegerField(),
- relative=models.ForeignKey('Target', models.CASCADE, related_name='clash'))
+ relative=models.ForeignKey("Target", models.CASCADE, related_name="clash"),
+ )
def test_fk_to_fk(self):
self._test_explicit_related_name_clash(
- target=models.ForeignKey('Another', models.CASCADE),
- relative=models.ForeignKey('Target', models.CASCADE, related_name='clash'))
+ target=models.ForeignKey("Another", models.CASCADE),
+ relative=models.ForeignKey("Target", models.CASCADE, related_name="clash"),
+ )
def test_fk_to_m2m(self):
self._test_explicit_related_name_clash(
- target=models.ManyToManyField('Another'),
- relative=models.ForeignKey('Target', models.CASCADE, related_name='clash'))
+ target=models.ManyToManyField("Another"),
+ relative=models.ForeignKey("Target", models.CASCADE, related_name="clash"),
+ )
def test_m2m_to_integer(self):
self._test_explicit_related_name_clash(
target=models.IntegerField(),
- relative=models.ManyToManyField('Target', related_name='clash'))
+ relative=models.ManyToManyField("Target", related_name="clash"),
+ )
def test_m2m_to_fk(self):
self._test_explicit_related_name_clash(
- target=models.ForeignKey('Another', models.CASCADE),
- relative=models.ManyToManyField('Target', related_name='clash'))
+ target=models.ForeignKey("Another", models.CASCADE),
+ relative=models.ManyToManyField("Target", related_name="clash"),
+ )
def test_m2m_to_m2m(self):
self._test_explicit_related_name_clash(
- target=models.ManyToManyField('Another'),
- relative=models.ManyToManyField('Target', related_name='clash'))
+ target=models.ManyToManyField("Another"),
+ relative=models.ManyToManyField("Target", related_name="clash"),
+ )
def _test_explicit_related_name_clash(self, target, relative):
class Another(models.Model):
@@ -1083,106 +1228,114 @@ class ExplicitRelatedNameClashTests(SimpleTestCase):
class Model(models.Model):
rel = relative
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Target.clash' for "
- "'invalid_models_tests.Model.rel' clashes with field name "
- "'invalid_models_tests.Target.clash'.",
- hint=(
- "Rename field 'invalid_models_tests.Target.clash', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.rel'."
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Target.clash' for "
+ "'invalid_models_tests.Model.rel' clashes with field name "
+ "'invalid_models_tests.Target.clash'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Target.clash', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.rel'."
+ ),
+ obj=Model._meta.get_field("rel"),
+ id="fields.E302",
),
- obj=Model._meta.get_field('rel'),
- id='fields.E302',
- ),
- Error(
- "Reverse query name for 'invalid_models_tests.Model.rel' "
- "clashes with field name 'invalid_models_tests.Target.clash'.",
- hint=(
- "Rename field 'invalid_models_tests.Target.clash', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.rel'."
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.rel' "
+ "clashes with field name 'invalid_models_tests.Target.clash'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Target.clash', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.rel'."
+ ),
+ obj=Model._meta.get_field("rel"),
+ id="fields.E303",
),
- obj=Model._meta.get_field('rel'),
- id='fields.E303',
- ),
- ])
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class ExplicitRelatedQueryNameClashTests(SimpleTestCase):
-
def test_fk_to_integer(self, related_name=None):
self._test_explicit_related_query_name_clash(
target=models.IntegerField(),
relative=models.ForeignKey(
- 'Target',
+ "Target",
models.CASCADE,
related_name=related_name,
- related_query_name='clash',
- )
+ related_query_name="clash",
+ ),
)
def test_hidden_fk_to_integer(self, related_name=None):
- self.test_fk_to_integer(related_name='+')
+ self.test_fk_to_integer(related_name="+")
def test_fk_to_fk(self, related_name=None):
self._test_explicit_related_query_name_clash(
- target=models.ForeignKey('Another', models.CASCADE),
+ target=models.ForeignKey("Another", models.CASCADE),
relative=models.ForeignKey(
- 'Target',
+ "Target",
models.CASCADE,
related_name=related_name,
- related_query_name='clash',
- )
+ related_query_name="clash",
+ ),
)
def test_hidden_fk_to_fk(self):
- self.test_fk_to_fk(related_name='+')
+ self.test_fk_to_fk(related_name="+")
def test_fk_to_m2m(self, related_name=None):
self._test_explicit_related_query_name_clash(
- target=models.ManyToManyField('Another'),
+ target=models.ManyToManyField("Another"),
relative=models.ForeignKey(
- 'Target',
+ "Target",
models.CASCADE,
related_name=related_name,
- related_query_name='clash',
- )
+ related_query_name="clash",
+ ),
)
def test_hidden_fk_to_m2m(self):
- self.test_fk_to_m2m(related_name='+')
+ self.test_fk_to_m2m(related_name="+")
def test_m2m_to_integer(self, related_name=None):
self._test_explicit_related_query_name_clash(
target=models.IntegerField(),
- relative=models.ManyToManyField('Target', related_name=related_name, related_query_name='clash'))
+ relative=models.ManyToManyField(
+ "Target", related_name=related_name, related_query_name="clash"
+ ),
+ )
def test_hidden_m2m_to_integer(self):
- self.test_m2m_to_integer(related_name='+')
+ self.test_m2m_to_integer(related_name="+")
def test_m2m_to_fk(self, related_name=None):
self._test_explicit_related_query_name_clash(
- target=models.ForeignKey('Another', models.CASCADE),
- relative=models.ManyToManyField('Target', related_name=related_name, related_query_name='clash'))
+ target=models.ForeignKey("Another", models.CASCADE),
+ relative=models.ManyToManyField(
+ "Target", related_name=related_name, related_query_name="clash"
+ ),
+ )
def test_hidden_m2m_to_fk(self):
- self.test_m2m_to_fk(related_name='+')
+ self.test_m2m_to_fk(related_name="+")
def test_m2m_to_m2m(self, related_name=None):
self._test_explicit_related_query_name_clash(
- target=models.ManyToManyField('Another'),
+ target=models.ManyToManyField("Another"),
relative=models.ManyToManyField(
- 'Target',
+ "Target",
related_name=related_name,
- related_query_name='clash',
- )
+ related_query_name="clash",
+ ),
)
def test_hidden_m2m_to_m2m(self):
- self.test_m2m_to_m2m(related_name='+')
+ self.test_m2m_to_m2m(related_name="+")
def _test_explicit_related_query_name_clash(self, target, relative):
class Another(models.Model):
@@ -1194,205 +1347,233 @@ class ExplicitRelatedQueryNameClashTests(SimpleTestCase):
class Model(models.Model):
rel = relative
- self.assertEqual(Model.check(), [
- Error(
- "Reverse query name for 'invalid_models_tests.Model.rel' "
- "clashes with field name 'invalid_models_tests.Target.clash'.",
- hint=(
- "Rename field 'invalid_models_tests.Target.clash', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.rel'."
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.rel' "
+ "clashes with field name 'invalid_models_tests.Target.clash'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Target.clash', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.rel'."
+ ),
+ obj=Model._meta.get_field("rel"),
+ id="fields.E303",
),
- obj=Model._meta.get_field('rel'),
- id='fields.E303',
- ),
- ])
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class SelfReferentialM2MClashTests(SimpleTestCase):
-
def test_clash_between_accessors(self):
class Model(models.Model):
- first_m2m = models.ManyToManyField('self', symmetrical=False)
- second_m2m = models.ManyToManyField('self', symmetrical=False)
-
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Model.model_set' for "
- "'invalid_models_tests.Model.first_m2m' clashes with reverse "
- "accessor for 'invalid_models_tests.Model.second_m2m'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.first_m2m' or "
- "'invalid_models_tests.Model.second_m2m'."
+ first_m2m = models.ManyToManyField("self", symmetrical=False)
+ second_m2m = models.ManyToManyField("self", symmetrical=False)
+
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Model.model_set' for "
+ "'invalid_models_tests.Model.first_m2m' clashes with reverse "
+ "accessor for 'invalid_models_tests.Model.second_m2m'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.first_m2m' or "
+ "'invalid_models_tests.Model.second_m2m'."
+ ),
+ obj=Model._meta.get_field("first_m2m"),
+ id="fields.E304",
),
- obj=Model._meta.get_field('first_m2m'),
- id='fields.E304',
- ),
- Error(
- "Reverse accessor 'Model.model_set' for "
- "'invalid_models_tests.Model.second_m2m' clashes with reverse "
- "accessor for 'invalid_models_tests.Model.first_m2m'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.second_m2m' or "
- "'invalid_models_tests.Model.first_m2m'."
+ Error(
+ "Reverse accessor 'Model.model_set' for "
+ "'invalid_models_tests.Model.second_m2m' clashes with reverse "
+ "accessor for 'invalid_models_tests.Model.first_m2m'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.second_m2m' or "
+ "'invalid_models_tests.Model.first_m2m'."
+ ),
+ obj=Model._meta.get_field("second_m2m"),
+ id="fields.E304",
),
- obj=Model._meta.get_field('second_m2m'),
- id='fields.E304',
- ),
- ])
+ ],
+ )
def test_accessor_clash(self):
class Model(models.Model):
model_set = models.ManyToManyField("self", symmetrical=False)
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Model.model_set' for "
- "'invalid_models_tests.Model.model_set' clashes with field "
- "name 'invalid_models_tests.Model.model_set'.",
- hint=(
- "Rename field 'invalid_models_tests.Model.model_set', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.model_set'."
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Model.model_set' for "
+ "'invalid_models_tests.Model.model_set' clashes with field "
+ "name 'invalid_models_tests.Model.model_set'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Model.model_set', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.model_set'."
+ ),
+ obj=Model._meta.get_field("model_set"),
+ id="fields.E302",
),
- obj=Model._meta.get_field('model_set'),
- id='fields.E302',
- ),
- ])
+ ],
+ )
def test_reverse_query_name_clash(self):
class Model(models.Model):
model = models.ManyToManyField("self", symmetrical=False)
- self.assertEqual(Model.check(), [
- Error(
- "Reverse query name for 'invalid_models_tests.Model.model' "
- "clashes with field name 'invalid_models_tests.Model.model'.",
- hint=(
- "Rename field 'invalid_models_tests.Model.model', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.model'."
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.model' "
+ "clashes with field name 'invalid_models_tests.Model.model'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Model.model', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.model'."
+ ),
+ obj=Model._meta.get_field("model"),
+ id="fields.E303",
),
- obj=Model._meta.get_field('model'),
- id='fields.E303',
- ),
- ])
+ ],
+ )
def test_clash_under_explicit_related_name(self):
class Model(models.Model):
clash = models.IntegerField()
- m2m = models.ManyToManyField("self", symmetrical=False, related_name='clash')
-
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Model.clash' for "
- "'invalid_models_tests.Model.m2m' clashes with field name "
- "'invalid_models_tests.Model.clash'.",
- hint=(
- "Rename field 'invalid_models_tests.Model.clash', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.m2m'."
+ m2m = models.ManyToManyField(
+ "self", symmetrical=False, related_name="clash"
+ )
+
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Model.clash' for "
+ "'invalid_models_tests.Model.m2m' clashes with field name "
+ "'invalid_models_tests.Model.clash'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Model.clash', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.m2m'."
+ ),
+ obj=Model._meta.get_field("m2m"),
+ id="fields.E302",
),
- obj=Model._meta.get_field('m2m'),
- id='fields.E302',
- ),
- Error(
- "Reverse query name for 'invalid_models_tests.Model.m2m' "
- "clashes with field name 'invalid_models_tests.Model.clash'.",
- hint=(
- "Rename field 'invalid_models_tests.Model.clash', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.m2m'."
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.m2m' "
+ "clashes with field name 'invalid_models_tests.Model.clash'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Model.clash', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.m2m'."
+ ),
+ obj=Model._meta.get_field("m2m"),
+ id="fields.E303",
),
- obj=Model._meta.get_field('m2m'),
- id='fields.E303',
- ),
- ])
+ ],
+ )
def test_valid_model(self):
class Model(models.Model):
- first = models.ManyToManyField("self", symmetrical=False, related_name='first_accessor')
- second = models.ManyToManyField("self", symmetrical=False, related_name='second_accessor')
+ first = models.ManyToManyField(
+ "self", symmetrical=False, related_name="first_accessor"
+ )
+ second = models.ManyToManyField(
+ "self", symmetrical=False, related_name="second_accessor"
+ )
self.assertEqual(Model.check(), [])
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class SelfReferentialFKClashTests(SimpleTestCase):
-
def test_accessor_clash(self):
class Model(models.Model):
model_set = models.ForeignKey("Model", models.CASCADE)
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Model.model_set' for "
- "'invalid_models_tests.Model.model_set' clashes with field "
- "name 'invalid_models_tests.Model.model_set'.",
- hint=(
- "Rename field 'invalid_models_tests.Model.model_set', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.model_set'."
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Model.model_set' for "
+ "'invalid_models_tests.Model.model_set' clashes with field "
+ "name 'invalid_models_tests.Model.model_set'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Model.model_set', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.model_set'."
+ ),
+ obj=Model._meta.get_field("model_set"),
+ id="fields.E302",
),
- obj=Model._meta.get_field('model_set'),
- id='fields.E302',
- ),
- ])
+ ],
+ )
def test_reverse_query_name_clash(self):
class Model(models.Model):
model = models.ForeignKey("Model", models.CASCADE)
- self.assertEqual(Model.check(), [
- Error(
- "Reverse query name for 'invalid_models_tests.Model.model' "
- "clashes with field name 'invalid_models_tests.Model.model'.",
- hint=(
- "Rename field 'invalid_models_tests.Model.model', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.model'."
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.model' "
+ "clashes with field name 'invalid_models_tests.Model.model'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Model.model', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.model'."
+ ),
+ obj=Model._meta.get_field("model"),
+ id="fields.E303",
),
- obj=Model._meta.get_field('model'),
- id='fields.E303',
- ),
- ])
+ ],
+ )
def test_clash_under_explicit_related_name(self):
class Model(models.Model):
clash = models.CharField(max_length=10)
- foreign = models.ForeignKey("Model", models.CASCADE, related_name='clash')
-
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Model.clash' for "
- "'invalid_models_tests.Model.foreign' clashes with field name "
- "'invalid_models_tests.Model.clash'.",
- hint=(
- "Rename field 'invalid_models_tests.Model.clash', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.foreign'."
+ foreign = models.ForeignKey("Model", models.CASCADE, related_name="clash")
+
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Model.clash' for "
+ "'invalid_models_tests.Model.foreign' clashes with field name "
+ "'invalid_models_tests.Model.clash'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Model.clash', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.foreign'."
+ ),
+ obj=Model._meta.get_field("foreign"),
+ id="fields.E302",
),
- obj=Model._meta.get_field('foreign'),
- id='fields.E302',
- ),
- Error(
- "Reverse query name for 'invalid_models_tests.Model.foreign' "
- "clashes with field name 'invalid_models_tests.Model.clash'.",
- hint=(
- "Rename field 'invalid_models_tests.Model.clash', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.foreign'."
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.foreign' "
+ "clashes with field name 'invalid_models_tests.Model.clash'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Model.clash', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.foreign'."
+ ),
+ obj=Model._meta.get_field("foreign"),
+ id="fields.E303",
),
- obj=Model._meta.get_field('foreign'),
- id='fields.E303',
- ),
- ])
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class ComplexClashTests(SimpleTestCase):
# New tests should not be included here, because this is a single,
@@ -1408,158 +1589,161 @@ class ComplexClashTests(SimpleTestCase):
class Model(models.Model):
src_safe = models.CharField(max_length=10)
- foreign_1 = models.ForeignKey(Target, models.CASCADE, related_name='id')
- foreign_2 = models.ForeignKey(Target, models.CASCADE, related_name='src_safe')
-
- m2m_1 = models.ManyToManyField(Target, related_name='id')
- m2m_2 = models.ManyToManyField(Target, related_name='src_safe')
-
- self.assertEqual(Model.check(), [
- Error(
- "Reverse accessor 'Target.id' for "
- "'invalid_models_tests.Model.foreign_1' clashes with field "
- "name 'invalid_models_tests.Target.id'.",
- hint=(
- "Rename field 'invalid_models_tests.Target.id', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.foreign_1'."
+ foreign_1 = models.ForeignKey(Target, models.CASCADE, related_name="id")
+ foreign_2 = models.ForeignKey(
+ Target, models.CASCADE, related_name="src_safe"
+ )
+
+ m2m_1 = models.ManyToManyField(Target, related_name="id")
+ m2m_2 = models.ManyToManyField(Target, related_name="src_safe")
+
+ self.assertEqual(
+ Model.check(),
+ [
+ Error(
+ "Reverse accessor 'Target.id' for "
+ "'invalid_models_tests.Model.foreign_1' clashes with field "
+ "name 'invalid_models_tests.Target.id'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Target.id', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.foreign_1'."
+ ),
+ obj=Model._meta.get_field("foreign_1"),
+ id="fields.E302",
),
- obj=Model._meta.get_field('foreign_1'),
- id='fields.E302',
- ),
- Error(
- "Reverse query name for 'invalid_models_tests.Model.foreign_1' "
- "clashes with field name 'invalid_models_tests.Target.id'.",
- hint=(
- "Rename field 'invalid_models_tests.Target.id', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.foreign_1'."
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.foreign_1' "
+ "clashes with field name 'invalid_models_tests.Target.id'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Target.id', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.foreign_1'."
+ ),
+ obj=Model._meta.get_field("foreign_1"),
+ id="fields.E303",
),
- obj=Model._meta.get_field('foreign_1'),
- id='fields.E303',
- ),
- Error(
- "Reverse accessor 'Target.id' for "
- "'invalid_models_tests.Model.foreign_1' clashes with reverse "
- "accessor for 'invalid_models_tests.Model.m2m_1'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.foreign_1' or "
- "'invalid_models_tests.Model.m2m_1'."
+ Error(
+ "Reverse accessor 'Target.id' for "
+ "'invalid_models_tests.Model.foreign_1' clashes with reverse "
+ "accessor for 'invalid_models_tests.Model.m2m_1'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.foreign_1' or "
+ "'invalid_models_tests.Model.m2m_1'."
+ ),
+ obj=Model._meta.get_field("foreign_1"),
+ id="fields.E304",
),
- obj=Model._meta.get_field('foreign_1'),
- id='fields.E304',
- ),
- Error(
- "Reverse query name for 'invalid_models_tests.Model.foreign_1' "
- "clashes with reverse query name for "
- "'invalid_models_tests.Model.m2m_1'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.foreign_1' or "
- "'invalid_models_tests.Model.m2m_1'."
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.foreign_1' "
+ "clashes with reverse query name for "
+ "'invalid_models_tests.Model.m2m_1'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.foreign_1' or "
+ "'invalid_models_tests.Model.m2m_1'."
+ ),
+ obj=Model._meta.get_field("foreign_1"),
+ id="fields.E305",
),
- obj=Model._meta.get_field('foreign_1'),
- id='fields.E305',
- ),
-
- Error(
- "Reverse accessor 'Target.src_safe' for "
- "'invalid_models_tests.Model.foreign_2' clashes with reverse "
- "accessor for 'invalid_models_tests.Model.m2m_2'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.foreign_2' or "
- "'invalid_models_tests.Model.m2m_2'."
+ Error(
+ "Reverse accessor 'Target.src_safe' for "
+ "'invalid_models_tests.Model.foreign_2' clashes with reverse "
+ "accessor for 'invalid_models_tests.Model.m2m_2'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.foreign_2' or "
+ "'invalid_models_tests.Model.m2m_2'."
+ ),
+ obj=Model._meta.get_field("foreign_2"),
+ id="fields.E304",
),
- obj=Model._meta.get_field('foreign_2'),
- id='fields.E304',
- ),
- Error(
- "Reverse query name for 'invalid_models_tests.Model.foreign_2' "
- "clashes with reverse query name for "
- "'invalid_models_tests.Model.m2m_2'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.foreign_2' or "
- "'invalid_models_tests.Model.m2m_2'."
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.foreign_2' "
+ "clashes with reverse query name for "
+ "'invalid_models_tests.Model.m2m_2'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.foreign_2' or "
+ "'invalid_models_tests.Model.m2m_2'."
+ ),
+ obj=Model._meta.get_field("foreign_2"),
+ id="fields.E305",
),
- obj=Model._meta.get_field('foreign_2'),
- id='fields.E305',
- ),
-
- Error(
- "Reverse accessor 'Target.id' for "
- "'invalid_models_tests.Model.m2m_1' clashes with field name "
- "'invalid_models_tests.Target.id'.",
- hint=(
- "Rename field 'invalid_models_tests.Target.id', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.m2m_1'."
+ Error(
+ "Reverse accessor 'Target.id' for "
+ "'invalid_models_tests.Model.m2m_1' clashes with field name "
+ "'invalid_models_tests.Target.id'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Target.id', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.m2m_1'."
+ ),
+ obj=Model._meta.get_field("m2m_1"),
+ id="fields.E302",
),
- obj=Model._meta.get_field('m2m_1'),
- id='fields.E302',
- ),
- Error(
- "Reverse query name for 'invalid_models_tests.Model.m2m_1' "
- "clashes with field name 'invalid_models_tests.Target.id'.",
- hint=(
- "Rename field 'invalid_models_tests.Target.id', or "
- "add/change a related_name argument to the definition for "
- "field 'invalid_models_tests.Model.m2m_1'."
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.m2m_1' "
+ "clashes with field name 'invalid_models_tests.Target.id'.",
+ hint=(
+ "Rename field 'invalid_models_tests.Target.id', or "
+ "add/change a related_name argument to the definition for "
+ "field 'invalid_models_tests.Model.m2m_1'."
+ ),
+ obj=Model._meta.get_field("m2m_1"),
+ id="fields.E303",
),
- obj=Model._meta.get_field('m2m_1'),
- id='fields.E303',
- ),
- Error(
- "Reverse accessor 'Target.id' for "
- "'invalid_models_tests.Model.m2m_1' clashes with reverse "
- "accessor for 'invalid_models_tests.Model.foreign_1'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.m2m_1' or "
- "'invalid_models_tests.Model.foreign_1'."
+ Error(
+ "Reverse accessor 'Target.id' for "
+ "'invalid_models_tests.Model.m2m_1' clashes with reverse "
+ "accessor for 'invalid_models_tests.Model.foreign_1'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.m2m_1' or "
+ "'invalid_models_tests.Model.foreign_1'."
+ ),
+ obj=Model._meta.get_field("m2m_1"),
+ id="fields.E304",
),
- obj=Model._meta.get_field('m2m_1'),
- id='fields.E304',
- ),
- Error(
- "Reverse query name for 'invalid_models_tests.Model.m2m_1' "
- "clashes with reverse query name for "
- "'invalid_models_tests.Model.foreign_1'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.m2m_1' or "
- "'invalid_models_tests.Model.foreign_1'."
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.m2m_1' "
+ "clashes with reverse query name for "
+ "'invalid_models_tests.Model.foreign_1'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.m2m_1' or "
+ "'invalid_models_tests.Model.foreign_1'."
+ ),
+ obj=Model._meta.get_field("m2m_1"),
+ id="fields.E305",
),
- obj=Model._meta.get_field('m2m_1'),
- id='fields.E305',
- ),
- Error(
- "Reverse accessor 'Target.src_safe' for "
- "'invalid_models_tests.Model.m2m_2' clashes with reverse "
- "accessor for 'invalid_models_tests.Model.foreign_2'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.m2m_2' or "
- "'invalid_models_tests.Model.foreign_2'."
+ Error(
+ "Reverse accessor 'Target.src_safe' for "
+ "'invalid_models_tests.Model.m2m_2' clashes with reverse "
+ "accessor for 'invalid_models_tests.Model.foreign_2'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.m2m_2' or "
+ "'invalid_models_tests.Model.foreign_2'."
+ ),
+ obj=Model._meta.get_field("m2m_2"),
+ id="fields.E304",
),
- obj=Model._meta.get_field('m2m_2'),
- id='fields.E304',
- ),
- Error(
- "Reverse query name for 'invalid_models_tests.Model.m2m_2' "
- "clashes with reverse query name for "
- "'invalid_models_tests.Model.foreign_2'.",
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Model.m2m_2' or "
- "'invalid_models_tests.Model.foreign_2'."
+ Error(
+ "Reverse query name for 'invalid_models_tests.Model.m2m_2' "
+ "clashes with reverse query name for "
+ "'invalid_models_tests.Model.foreign_2'.",
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Model.m2m_2' or "
+ "'invalid_models_tests.Model.foreign_2'."
+ ),
+ obj=Model._meta.get_field("m2m_2"),
+ id="fields.E305",
),
- obj=Model._meta.get_field('m2m_2'),
- id='fields.E305',
- ),
- ])
+ ],
+ )
def test_clash_parent_link(self):
class Parent(models.Model):
@@ -1569,136 +1753,170 @@ class ComplexClashTests(SimpleTestCase):
other_parent = models.OneToOneField(Parent, models.CASCADE)
errors = [
- ('fields.E304', 'accessor', " 'Parent.child'", 'parent_ptr', 'other_parent'),
- ('fields.E305', 'query name', '', 'parent_ptr', 'other_parent'),
- ('fields.E304', 'accessor', " 'Parent.child'", 'other_parent', 'parent_ptr'),
- ('fields.E305', 'query name', '', 'other_parent', 'parent_ptr'),
+ (
+ "fields.E304",
+ "accessor",
+ " 'Parent.child'",
+ "parent_ptr",
+ "other_parent",
+ ),
+ ("fields.E305", "query name", "", "parent_ptr", "other_parent"),
+ (
+ "fields.E304",
+ "accessor",
+ " 'Parent.child'",
+ "other_parent",
+ "parent_ptr",
+ ),
+ ("fields.E305", "query name", "", "other_parent", "parent_ptr"),
]
- self.assertEqual(Child.check(), [
- Error(
- "Reverse %s%s for 'invalid_models_tests.Child.%s' clashes with "
- "reverse %s for 'invalid_models_tests.Child.%s'."
- % (attr, rel_name, field_name, attr, clash_name),
- hint=(
- "Add or change a related_name argument to the definition "
- "for 'invalid_models_tests.Child.%s' or "
- "'invalid_models_tests.Child.%s'." % (field_name, clash_name)
- ),
- obj=Child._meta.get_field(field_name),
- id=error_id,
- )
- for error_id, attr, rel_name, field_name, clash_name in errors
- ])
+ self.assertEqual(
+ Child.check(),
+ [
+ Error(
+ "Reverse %s%s for 'invalid_models_tests.Child.%s' clashes with "
+ "reverse %s for 'invalid_models_tests.Child.%s'."
+ % (attr, rel_name, field_name, attr, clash_name),
+ hint=(
+ "Add or change a related_name argument to the definition "
+ "for 'invalid_models_tests.Child.%s' or "
+ "'invalid_models_tests.Child.%s'." % (field_name, clash_name)
+ ),
+ obj=Child._meta.get_field(field_name),
+ id=error_id,
+ )
+ for error_id, attr, rel_name, field_name, clash_name in errors
+ ],
+ )
-@isolate_apps('invalid_models_tests')
+@isolate_apps("invalid_models_tests")
class M2mThroughFieldsTests(SimpleTestCase):
def test_m2m_field_argument_validation(self):
"""
ManyToManyField accepts the ``through_fields`` kwarg
only if an intermediary table is specified.
"""
+
class Fan(models.Model):
pass
- with self.assertRaisesMessage(ValueError, 'Cannot specify through_fields without a through model'):
- models.ManyToManyField(Fan, through_fields=('f1', 'f2'))
+ with self.assertRaisesMessage(
+ ValueError, "Cannot specify through_fields without a through model"
+ ):
+ models.ManyToManyField(Fan, through_fields=("f1", "f2"))
def test_invalid_order(self):
"""
Mixing up the order of link fields to ManyToManyField.through_fields
triggers validation errors.
"""
+
class Fan(models.Model):
pass
class Event(models.Model):
- invitees = models.ManyToManyField(Fan, through='Invitation', through_fields=('invitee', 'event'))
+ invitees = models.ManyToManyField(
+ Fan, through="Invitation", through_fields=("invitee", "event")
+ )
class Invitation(models.Model):
event = models.ForeignKey(Event, models.CASCADE)
invitee = models.ForeignKey(Fan, models.CASCADE)
- inviter = models.ForeignKey(Fan, models.CASCADE, related_name='+')
-
- field = Event._meta.get_field('invitees')
- self.assertEqual(field.check(from_model=Event), [
- Error(
- "'Invitation.invitee' is not a foreign key to 'Event'.",
- hint="Did you mean one of the following foreign keys to 'Event': event?",
- obj=field,
- id='fields.E339',
- ),
- Error(
- "'Invitation.event' is not a foreign key to 'Fan'.",
- hint="Did you mean one of the following foreign keys to 'Fan': invitee, inviter?",
- obj=field,
- id='fields.E339',
- ),
- ])
+ inviter = models.ForeignKey(Fan, models.CASCADE, related_name="+")
+
+ field = Event._meta.get_field("invitees")
+ self.assertEqual(
+ field.check(from_model=Event),
+ [
+ Error(
+ "'Invitation.invitee' is not a foreign key to 'Event'.",
+ hint="Did you mean one of the following foreign keys to 'Event': event?",
+ obj=field,
+ id="fields.E339",
+ ),
+ Error(
+ "'Invitation.event' is not a foreign key to 'Fan'.",
+ hint="Did you mean one of the following foreign keys to 'Fan': invitee, inviter?",
+ obj=field,
+ id="fields.E339",
+ ),
+ ],
+ )
def test_invalid_field(self):
"""
Providing invalid field names to ManyToManyField.through_fields
triggers validation errors.
"""
+
class Fan(models.Model):
pass
class Event(models.Model):
invitees = models.ManyToManyField(
Fan,
- through='Invitation',
- through_fields=('invalid_field_1', 'invalid_field_2'),
+ through="Invitation",
+ through_fields=("invalid_field_1", "invalid_field_2"),
)
class Invitation(models.Model):
event = models.ForeignKey(Event, models.CASCADE)
invitee = models.ForeignKey(Fan, models.CASCADE)
- inviter = models.ForeignKey(Fan, models.CASCADE, related_name='+')
-
- field = Event._meta.get_field('invitees')
- self.assertEqual(field.check(from_model=Event), [
- Error(
- "The intermediary model 'invalid_models_tests.Invitation' has no field 'invalid_field_1'.",
- hint="Did you mean one of the following foreign keys to 'Event': event?",
- obj=field,
- id='fields.E338',
- ),
- Error(
- "The intermediary model 'invalid_models_tests.Invitation' has no field 'invalid_field_2'.",
- hint="Did you mean one of the following foreign keys to 'Fan': invitee, inviter?",
- obj=field,
- id='fields.E338',
- ),
- ])
+ inviter = models.ForeignKey(Fan, models.CASCADE, related_name="+")
+
+ field = Event._meta.get_field("invitees")
+ self.assertEqual(
+ field.check(from_model=Event),
+ [
+ Error(
+ "The intermediary model 'invalid_models_tests.Invitation' has no field 'invalid_field_1'.",
+ hint="Did you mean one of the following foreign keys to 'Event': event?",
+ obj=field,
+ id="fields.E338",
+ ),
+ Error(
+ "The intermediary model 'invalid_models_tests.Invitation' has no field 'invalid_field_2'.",
+ hint="Did you mean one of the following foreign keys to 'Fan': invitee, inviter?",
+ obj=field,
+ id="fields.E338",
+ ),
+ ],
+ )
def test_explicit_field_names(self):
"""
If ``through_fields`` kwarg is given, it must specify both
link fields of the intermediary table.
"""
+
class Fan(models.Model):
pass
class Event(models.Model):
- invitees = models.ManyToManyField(Fan, through='Invitation', through_fields=(None, 'invitee'))
+ invitees = models.ManyToManyField(
+ Fan, through="Invitation", through_fields=(None, "invitee")
+ )
class Invitation(models.Model):
event = models.ForeignKey(Event, models.CASCADE)
invitee = models.ForeignKey(Fan, models.CASCADE)
- inviter = models.ForeignKey(Fan, models.CASCADE, related_name='+')
-
- field = Event._meta.get_field('invitees')
- self.assertEqual(field.check(from_model=Event), [
- Error(
- "Field specifies 'through_fields' but does not provide the names "
- "of the two link fields that should be used for the relation "
- "through model 'invalid_models_tests.Invitation'.",
- hint="Make sure you specify 'through_fields' as through_fields=('field1', 'field2')",
- obj=field,
- id='fields.E337',
- ),
- ])
+ inviter = models.ForeignKey(Fan, models.CASCADE, related_name="+")
+
+ field = Event._meta.get_field("invitees")
+ self.assertEqual(
+ field.check(from_model=Event),
+ [
+ Error(
+ "Field specifies 'through_fields' but does not provide the names "
+ "of the two link fields that should be used for the relation "
+ "through model 'invalid_models_tests.Invitation'.",
+ hint="Make sure you specify 'through_fields' as through_fields=('field1', 'field2')",
+ obj=field,
+ id="fields.E337",
+ ),
+ ],
+ )
def test_superset_foreign_object(self):
class Parent(models.Model):
@@ -1707,7 +1925,7 @@ class M2mThroughFieldsTests(SimpleTestCase):
c = models.PositiveIntegerField()
class Meta:
- unique_together = (('a', 'b', 'c'),)
+ unique_together = (("a", "b", "c"),)
class Child(models.Model):
a = models.PositiveIntegerField()
@@ -1716,25 +1934,28 @@ class M2mThroughFieldsTests(SimpleTestCase):
parent = models.ForeignObject(
Parent,
on_delete=models.SET_NULL,
- from_fields=('a', 'b'),
- to_fields=('a', 'b'),
- related_name='children',
+ from_fields=("a", "b"),
+ to_fields=("a", "b"),
+ related_name="children",
)
- field = Child._meta.get_field('parent')
- self.assertEqual(field.check(from_model=Child), [
- Error(
- "No subset of the fields 'a', 'b' on model 'Parent' is unique.",
- hint=(
- 'Mark a single field as unique=True or add a set of '
- 'fields to a unique constraint (via unique_together or a '
- 'UniqueConstraint (without condition) in the model '
- 'Meta.constraints).'
+ field = Child._meta.get_field("parent")
+ self.assertEqual(
+ field.check(from_model=Child),
+ [
+ Error(
+ "No subset of the fields 'a', 'b' on model 'Parent' is unique.",
+ hint=(
+ "Mark a single field as unique=True or add a set of "
+ "fields to a unique constraint (via unique_together or a "
+ "UniqueConstraint (without condition) in the model "
+ "Meta.constraints)."
+ ),
+ obj=field,
+ id="fields.E310",
),
- obj=field,
- id='fields.E310',
- ),
- ])
+ ],
+ )
def test_intersection_foreign_object(self):
class Parent(models.Model):
@@ -1744,7 +1965,7 @@ class M2mThroughFieldsTests(SimpleTestCase):
d = models.PositiveIntegerField()
class Meta:
- unique_together = (('a', 'b', 'c'),)
+ unique_together = (("a", "b", "c"),)
class Child(models.Model):
a = models.PositiveIntegerField()
@@ -1754,22 +1975,25 @@ class M2mThroughFieldsTests(SimpleTestCase):
parent = models.ForeignObject(
Parent,
on_delete=models.SET_NULL,
- from_fields=('a', 'b', 'd'),
- to_fields=('a', 'b', 'd'),
- related_name='children',
+ from_fields=("a", "b", "d"),
+ to_fields=("a", "b", "d"),
+ related_name="children",
)
- field = Child._meta.get_field('parent')
- self.assertEqual(field.check(from_model=Child), [
- Error(
- "No subset of the fields 'a', 'b', 'd' on model 'Parent' is unique.",
- hint=(
- 'Mark a single field as unique=True or add a set of '
- 'fields to a unique constraint (via unique_together or a '
- 'UniqueConstraint (without condition) in the model '
- 'Meta.constraints).'
+ field = Child._meta.get_field("parent")
+ self.assertEqual(
+ field.check(from_model=Child),
+ [
+ Error(
+ "No subset of the fields 'a', 'b', 'd' on model 'Parent' is unique.",
+ hint=(
+ "Mark a single field as unique=True or add a set of "
+ "fields to a unique constraint (via unique_together or a "
+ "UniqueConstraint (without condition) in the model "
+ "Meta.constraints)."
+ ),
+ obj=field,
+ id="fields.E310",
),
- obj=field,
- id='fields.E310',
- ),
- ])
+ ],
+ )