#28714: Django Makemigrations don't check if field name from indexes exists on
model before creating a migration.
-------------------------------------+-------------------------------------
               Reporter:  Gabriel    |          Owner:  nobody
                   Type:  Bug        |         Status:  new
              Component:             |        Version:  1.11
  Migrations                         |       Keywords:  indexes, migrate,
               Severity:  Normal     |  makemigrations
           Triage Stage:             |      Has patch:  0
  Unreviewed                         |
    Needs documentation:  0          |    Needs tests:  0
Patch needs improvement:  0          |  Easy pickings:  0
                  UI/UX:  0          |
-------------------------------------+-------------------------------------
 When using makemigration with indexes on class Meta in the Model Django
 don't check whether the field name in fields parameter exists on Model.

 Because of this both the migration files (in migrations/*.py) and the
 model class on model.py will have a index that referrer to a non existing
 field, so when **manage.py migrate** is run, the expection
 FieldDoesNotExist will be raised, but in this moment the programmer will
 have to edit both the migration file and model class to fix the error,
 especially if is not possible to remove the migrations file or is more
 convenient to edit the migration in projects with many Apps and many
 dependency between those Apps.

 Would be more convenient if makemigration before generate the new
 migration files did this verification.

 Example of model's code with wrong field name ("''names''") on indexes:

 {{{
 class ItemType(models.Model):
         name = models.CharField(_('Name'), unique=True, max_length=255)

         class Meta:
                 managed = True
                 db_table = 'item_type'
                 ordering = ['name']

                 indexes = [
                         models.Index(fields=['id'],
 name='item_type_index_1'),
                         models.Index(fields=['-id'],
 name='item_type_index_2'),
                         models.Index(fields=['names'],
 name='item_type_index_3'),
                         models.Index(fields=['-names'],
 name='item_type_index_4')
                 ]
 }}}

 This code will not raise any exception on **makemigrations**, only the
 generated code on migration file will when **migrate** is used:

 {{{
        migrations.AddIndex(
             model_name='itemtype',
             index=models.Index(fields=['names'],
 name='item_type_index_3'),
         ),
         migrations.AddIndex(
             model_name='itemtype',
             index=models.Index(fields=['-names'],
 name='item_type_index_4'),
         ),
 }}}

 Traceback (manage.py migrate):


 {{{
 Traceback (most recent call last):
   File "D:\Project-2015\cultural\manage.py", line 10, in <module>
     execute_from_command_line(sys.argv)
   File "C:\Python36\lib\site-packages\django\core\management\__init__.py",
 line 364, in execute_from_command_line
     utility.execute()
   File "C:\Python36\lib\site-packages\django\core\management\__init__.py",
 line 356, in execute
     self.fetch_command(subcommand).run_from_argv(self.argv)
   File "C:\Python36\lib\site-packages\django\core\management\base.py",
 line 283, in run_from_argv
     self.execute(*args, **cmd_options)
   File "C:\Python36\lib\site-packages\django\core\management\base.py",
 line 330, in execute
     output = self.handle(*args, **options)
   File "C:\Python36\lib\site-
 packages\django\core\management\commands\migrate.py", line 204, in handle
     fake_initial=fake_initial,
   File "C:\Python36\lib\site-packages\django\db\migrations\executor.py",
 line 115, in migrate
     state = self._migrate_all_forwards(state, plan, full_plan, fake=fake,
 fake_initial=fake_initial)
   File "C:\Python36\lib\site-packages\django\db\migrations\executor.py",
 line 145, in _migrate_all_forwards
     state = self.apply_migration(state, migration, fake=fake,
 fake_initial=fake_initial)
   File "C:\Python36\lib\site-packages\django\db\migrations\executor.py",
 line 244, in apply_migration
     state = migration.apply(state, schema_editor)
   File "C:\Python36\lib\site-packages\django\db\migrations\migration.py",
 line 129, in apply
     operation.database_forwards(self.app_label, schema_editor, old_state,
 project_state)
   File "C:\Python36\lib\site-
 packages\django\db\migrations\operations\models.py", line 788, in
 database_forwards
     schema_editor.add_index(model, self.index)
   File "C:\Python36\lib\site-packages\django\db\backends\base\schema.py",
 line 331, in add_index
     self.execute(index.create_sql(model, self))
   File "C:\Python36\lib\site-packages\django\db\models\indexes.py", line
 65, in create_sql
     sql_parameters = self.get_sql_create_template_values(model,
 schema_editor, using)
   File "C:\Python36\lib\site-packages\django\db\models\indexes.py", line
 48, in get_sql_create_template_values
     fields = [model._meta.get_field(field_name) for field_name, order in
 self.fields_orders]
   File "C:\Python36\lib\site-packages\django\db\models\indexes.py", line
 48, in <listcomp>
     fields = [model._meta.get_field(field_name) for field_name, order in
 self.fields_orders]
   File "C:\Python36\lib\site-packages\django\db\models\options.py", line
 619, in get_field
     raise FieldDoesNotExist("%s has no field named '%s'" %
 (self.object_name, field_name))
 django.core.exceptions.FieldDoesNotExist: ItemType has no field named
 'names'
 }}}


 Attached is this model example with a incorrect index field name that will
 not raise exception on makemigration only on migrate.

 This was checked on Django 1.11.5 with Python 3.6.2 on Windows 10 64bits.

 To reproduce this error:
 1. Add the Item App to a existing Django project
 2. Run manage.py makemigrations item
 3. Run manage.py migrate

-- 
Ticket URL: <https://code.djangoproject.com/ticket/28714>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/051.0e4051b5b2cc7d0728c44c27f46ad5fd%40djangoproject.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to