mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	Fixed #28714 -- Added system checks for invalid model field names in Meta.indexes.
Thanks Gabriel for the report and Adam Johnson for the review.
This commit is contained in:
		| @@ -1203,6 +1203,7 @@ class Model(metaclass=ModelBase): | ||||
|             errors += [ | ||||
|                 *cls._check_index_together(), | ||||
|                 *cls._check_unique_together(), | ||||
|                 *cls._check_indexes(), | ||||
|                 *cls._check_ordering(), | ||||
|             ] | ||||
|  | ||||
| @@ -1474,6 +1475,12 @@ class Model(metaclass=ModelBase): | ||||
|                 errors.extend(cls._check_local_fields(fields, "unique_together")) | ||||
|             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 | ||||
|   | ||||
| @@ -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>``. | ||||
|   | ||||
| @@ -219,6 +219,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): | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user