summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorhui shang <shangdahao@gmail.com>2017-12-28 07:56:24 +0800
committerTim Graham <timograham@gmail.com>2017-12-27 18:56:24 -0500
commitf1aa58479cdc6051dd2e97feca2d584c43aee1e7 (patch)
tree1f59109f6c02462716ae76bb45c26548c918164b
parent1d00923848d504c6132019492b8d5a6cdf8261db (diff)
Fixed #28714 -- Added system checks for invalid model field names in Meta.indexes.
Thanks Gabriel for the report and Adam Johnson for the review.
-rw-r--r--django/db/models/base.py7
-rw-r--r--docs/ref/checks.txt6
-rw-r--r--tests/invalid_models_tests/test_models.py53
3 files changed, 63 insertions, 3 deletions
diff --git a/django/db/models/base.py b/django/db/models/base.py
index 36be70beb5..2588ee3ff6 100644
--- a/django/db/models/base.py
+++ b/django/db/models/base.py
@@ -1203,6 +1203,7 @@ class Model(metaclass=ModelBase):
errors += [
*cls._check_index_together(),
*cls._check_unique_together(),
+ *cls._check_indexes(),
*cls._check_ordering(),
]
@@ -1475,6 +1476,12 @@ class Model(metaclass=ModelBase):
return errors
@classmethod
+ def _check_indexes(cls):
+ """Check the fields of indexes."""
+ fields = [field for index in cls._meta.indexes for field, _ in index.fields_orders]
+ return cls._check_local_fields(fields, 'indexes')
+
+ @classmethod
def _check_local_fields(cls, fields, option):
from django.db import models
diff --git a/docs/ref/checks.txt b/docs/ref/checks.txt
index 9b3f1be356..db86c49ee0 100644
--- a/docs/ref/checks.txt
+++ b/docs/ref/checks.txt
@@ -265,16 +265,16 @@ Models
* **models.E009**: All ``index_together`` elements must be lists or tuples.
* **models.E010**: ``unique_together`` must be a list or tuple.
* **models.E011**: All ``unique_together`` elements must be lists or tuples.
-* **models.E012**: ``index_together/unique_together`` refers to the
+* **models.E012**: ``indexes/index_together/unique_together`` refers to the
nonexistent field ``<field name>``.
-* **models.E013**: ``index_together/unique_together`` refers to a
+* **models.E013**: ``indexes/index_together/unique_together`` refers to a
``ManyToManyField`` ``<field name>``, but ``ManyToManyField``\s are not
supported for that option.
* **models.E014**: ``ordering`` must be a tuple or list (even if you want to
order by only one field).
* **models.E015**: ``ordering`` refers to the nonexistent field
``<field name>``.
-* **models.E016**: ``index_together/unique_together`` refers to field
+* **models.E016**: ``indexes/index_together/unique_together`` refers to field
``<field_name>`` which is not local to model ``<model>``.
* **models.E017**: Proxy model ``<model>`` contains model fields.
* **models.E018**: Autogenerated column name too long for field ``<field>``.
diff --git a/tests/invalid_models_tests/test_models.py b/tests/invalid_models_tests/test_models.py
index 4a3e5e3a02..71e1b83a3f 100644
--- a/tests/invalid_models_tests/test_models.py
+++ b/tests/invalid_models_tests/test_models.py
@@ -220,6 +220,59 @@ class UniqueTogetherTests(SimpleTestCase):
@isolate_apps('invalid_models_tests')
+class IndexesTests(SimpleTestCase):
+
+ def test_pointing_to_missing_field(self):
+ class Model(models.Model):
+ class Meta:
+ 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',
+ ),
+ ])
+
+ def test_pointing_to_m2m_field(self):
+ class Model(models.Model):
+ m2m = models.ManyToManyField('self')
+
+ class Meta:
+ 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',
+ ),
+ ])
+
+ def test_pointing_to_non_local_field(self):
+ class Foo(models.Model):
+ field1 = models.IntegerField()
+
+ class Bar(Foo):
+ field2 = models.IntegerField()
+
+ class Meta:
+ 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',
+ ),
+ ])
+
+
+@isolate_apps('invalid_models_tests')
class FieldNamesTests(SimpleTestCase):
def test_ending_with_underscore(self):