diff options
| author | hui shang <shangdahao@gmail.com> | 2017-12-28 07:56:24 +0800 |
|---|---|---|
| committer | Tim Graham <timograham@gmail.com> | 2017-12-27 18:56:24 -0500 |
| commit | f1aa58479cdc6051dd2e97feca2d584c43aee1e7 (patch) | |
| tree | 1f59109f6c02462716ae76bb45c26548c918164b | |
| parent | 1d00923848d504c6132019492b8d5a6cdf8261db (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.py | 7 | ||||
| -rw-r--r-- | docs/ref/checks.txt | 6 | ||||
| -rw-r--r-- | tests/invalid_models_tests/test_models.py | 53 |
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): |
