Opened 7 years ago
Closed 7 years ago
#30090 closed Bug (needsinfo)
Cannot reverse MySQL DB migration when model has unique_together and one of the fields has db_index=True
| 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 )
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 (5)
comment:1 by , 7 years ago
| Description: | modified (diff) |
|---|
comment:2 by , 7 years ago
comment:3 by , 7 years ago
Hi Andy. Do you have capacity to put your test case into a PR on GitHub so that we can see it in the CI? (I can do it if not but you've likely already got it bootstrapped, so that'd save a few cycles. 🙂)
Thanks
comment:4 by , 7 years ago
Hi Carlton. I added a test but couldn't reproduce the error in the test suite against a branch based off master. I went back to the test project I made (where the code above is copied from and using Django 2.1.5) and that too seems to be working now. I'm very confused. The test project is isolated in its own virtualenv and no dependencies have been changed since I created the test project and filed the bug report.
So at this point I'm unable to reproduce the issue. Perhaps we should close this and if I can figure out how to repro it again I'll reopen this or file a new bug.
comment:5 by , 7 years ago
| Resolution: | → needsinfo |
|---|---|
| Status: | new → closed |
… if I can figure out how to repro it again I'll reopen this …
OK. Lets do that. A test case is obviously best but a test project would do. 👍
Thanks for the follow up Andy.
FYI I just tested on SQLite and could not reproduce this issue.