Opened 6 years ago

Last modified 6 years ago

#30090 closed Bug

Cannot reverse MySQL DB migration when model has unique_together and one of the fields has db_index=True — at Version 1

Reported by: Andy McCurdy Owned by: nobody
Component: Migrations Version: 2.1
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by Andy McCurdy)

I'm seeing errors attempting to rollback a migration when a model field that has db_index=True is also included within a unique_together constraint. From my testing this only happens when the field with the db_index=True attribute is included in the unique_together constraint after another field that does not have db_index specified. In the example below, reversing the order of the fields in the unique_together allows the migration to rollback without issue.

I have only tested this on MySQL. Other backends may or may not be affected as well.

The following models.py and 0001_initial.py files demonstrate the error. I'm using Django 2.1.5 and mysqlclient 1.3.14.

from django.db import models


class TestModel(models.Model):
    field_a = models.IntegerField(db_index=True)
    field_b = models.IntegerField()

    class Meta:
        unique_together = (
            ('field_b', 'field_a'),
        )

This produces the following migration:

# Generated by Django 2.1.5 on 2019-01-10 00:11

from django.db import migrations, models


class Migration(migrations.Migration):

    initial = True

    dependencies = [
    ]

    operations = [
        migrations.CreateModel(
            name='TestModel',
            fields=[
                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('field_a', models.IntegerField(db_index=True)),
                ('field_b', models.IntegerField()),
            ],
        ),
        migrations.AlterUniqueTogether(
            name='testmodel',
            unique_together={('field_b', 'field_a')},
        ),
    ]

The migration is applied cleanly. When rolling it back I get this error:

Operations to perform:
  Unapply all migrations: mysql_error
Running migrations:
  Rendering model states... DONE
  Unapplying mysql_error.0001_initial...Traceback (most recent call last):
  File "./manage.py", line 15, in <module>
    execute_from_command_line(sys.argv)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/core/management/__init__.py", line 381, in execute_from_command_line
    utility.execute()
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/core/management/__init__.py", line 375, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/core/management/base.py", line 316, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/core/management/base.py", line 353, in execute
    output = self.handle(*args, **options)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/core/management/base.py", line 83, in wrapped
    res = handle_func(*args, **kwargs)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/core/management/commands/migrate.py", line 203, in handle
    fake_initial=fake_initial,
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/db/migrations/executor.py", line 121, in migrate
    state = self._migrate_all_backwards(plan, full_plan, fake=fake)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/db/migrations/executor.py", line 196, in _migrate_all_backwards
    self.unapply_migration(states[migration], migration, fake=fake)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/db/migrations/executor.py", line 262, in unapply_migration
    state = migration.unapply(state, schema_editor)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/db/migrations/migration.py", line 175, in unapply
    operation.database_backwards(self.app_label, schema_editor, from_state, to_state)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/db/migrations/operations/models.py", line 518, in database_backwards
    return self.database_forwards(app_label, schema_editor, from_state, to_state)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/db/migrations/operations/models.py", line 514, in database_forwards
    getattr(new_model._meta, self.option_name, set()),
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/db/backends/base/schema.py", line 356, in alter_unique_together
    self._delete_composed_index(model, fields, {'unique': True}, self.sql_delete_unique)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/db/backends/mysql/schema.py", line 82, in _delete_composed_index
    return super()._delete_composed_index(model, fields, *args)
  File "/Users/andy/.pyenv/versions/django-test/lib/python3.7/site-packages/django/db/backends/base/schema.py", line 385, in _delete_composed_index
    ", ".join(columns),
ValueError: Found wrong number (0) of constraints for mysql_error_testmodel(field_b, field_a)

Change History (1)

comment:1 by Andy McCurdy, 6 years ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top