Opened 6 years ago
Closed 6 years ago
#30276 closed Bug (fixed)
reverse DeleteModel migration with a primary key OneToOneField fails in MySQL
Reported by: | Florian Zimmermann | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | 2.1 |
Severity: | Normal | Keywords: | migrations, mysql |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Preparations
In a new app create two models (without the dummy
field this would trigger #27746):
from django.db import models class One(models.Model): pass class Two(models.Model): one = models.OneToOneField(One, primary_key=True, on_delete=models.CASCADE) dummy = models.IntegerField()
python manage.py makemigrations
yields this migration:
from django.db import migrations, models import django.db.models.deletion class Migration(migrations.Migration): initial = True dependencies = [] operations = [ migrations.CreateModel( name='One', fields=[ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ], ), migrations.CreateModel( name='Two', fields=[ ('one', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, primary_key=True, serialize=False, to='bug.One')), ('dummy', models.IntegerField()), ], ), ]
Then remove the Two
model:
from django.db import models class One(models.Model): pass #class Two(models.Model): # one = models.OneToOneField(One, primary_key=True, on_delete=models.CASCADE) # dummy = models.IntegerField()
which yields the offending migration:
from django.db import migrations class Migration(migrations.Migration): dependencies = [ ('bug', '0001_initial'), ] operations = [ migrations.RemoveField( model_name='two', name='one', ), migrations.DeleteModel( name='Two', ), ]
Triggering the bug
Apply both migrations and then unapply the second migration:
python manage.py migrate bug python manage.py migrate bug 0001
Operations to perform: Target specific migration: 0001_initial, from bug Running migrations: Rendering model states... DONE Unapplying bug.0002_auto_20190321_1219...Traceback (most recent call last): File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute return self.cursor.execute(sql, params) File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\mysql\base.py", line 71, in execute return self.cursor.execute(query, args) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\cursors.py", line 250, in execute self.errorhandler(self, exc, value) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\connections.py", line 50, in defaulterrorhandler raise errorvalue File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\cursors.py", line 247, in execute res = self._query(query) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\cursors.py", line 412, in _query rowcount = self._do_query(q) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\cursors.py", line 375, in _do_query db.query(q) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\connections.py", line 276, in query _mysql.connection.query(self, query) _mysql_exceptions.OperationalError: (1068, 'Multiple primary key defined') The above exception was the direct cause of the following exception: Traceback (most recent call last): File "manage.py", line 15, in <module> execute_from_command_line(sys.argv) File "D:\temp\django-bug\venv\lib\site-packages\django\core\management\__init__.py", line 381, in execute_from_command_line utility.execute() File "D:\temp\django-bug\venv\lib\site-packages\django\core\management\__init__.py", line 375, in execute self.fetch_command(subcommand).run_from_argv(self.argv) File "D:\temp\django-bug\venv\lib\site-packages\django\core\management\base.py", line 316, in run_from_argv self.execute(*args, **cmd_options) File "D:\temp\django-bug\venv\lib\site-packages\django\core\management\base.py", line 353, in execute output = self.handle(*args, **options) File "D:\temp\django-bug\venv\lib\site-packages\django\core\management\base.py", line 83, in wrapped res = handle_func(*args, **kwargs) File "D:\temp\django-bug\venv\lib\site-packages\django\core\management\commands\migrate.py", line 203, in handle fake_initial=fake_initial, File "D:\temp\django-bug\venv\lib\site-packages\django\db\migrations\executor.py", line 121, in migrate state = self._migrate_all_backwards(plan, full_plan, fake=fake) File "D:\temp\django-bug\venv\lib\site-packages\django\db\migrations\executor.py", line 196, in _migrate_all_backwards self.unapply_migration(states[migration], migration, fake=fake) File "D:\temp\django-bug\venv\lib\site-packages\django\db\migrations\executor.py", line 262, in unapply_migration state = migration.unapply(state, schema_editor) File "D:\temp\django-bug\venv\lib\site-packages\django\db\migrations\migration.py", line 175, in unapply operation.database_backwards(self.app_label, schema_editor, from_state, to_state) File "D:\temp\django-bug\venv\lib\site-packages\django\db\migrations\operations\fields.py", line 156, in database_backwards schema_editor.add_field(from_model, to_model._meta.get_field(self.name)) File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\mysql\schema.py", line 42, in add_field super().add_field(model, field) File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\base\schema.py", line 435, in add_field self.execute(sql, params) File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\base\schema.py", line 133, in execute cursor.execute(sql, params) File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\utils.py", line 100, in execute return super().execute(sql, params) File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\utils.py", line 68, in execute return self._execute_with_wrappers(sql, params, many=False, executor=self._execute) File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\utils.py", line 77, in _execute_with_wrappers return executor(sql, params, many, context) File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute return self.cursor.execute(sql, params) File "D:\temp\django-bug\venv\lib\site-packages\django\db\utils.py", line 89, in __exit__ raise dj_exc_value.with_traceback(traceback) from exc_value File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\utils.py", line 85, in _execute return self.cursor.execute(sql, params) File "D:\temp\django-bug\venv\lib\site-packages\django\db\backends\mysql\base.py", line 71, in execute return self.cursor.execute(query, args) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\cursors.py", line 250, in execute self.errorhandler(self, exc, value) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\connections.py", line 50, in defaulterrorhandler raise errorvalue File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\cursors.py", line 247, in execute res = self._query(query) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\cursors.py", line 412, in _query rowcount = self._do_query(q) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\cursors.py", line 375, in _do_query db.query(q) File "D:\temp\django-bug\venv\lib\site-packages\MySQLdb\connections.py", line 276, in query _mysql.connection.query(self, query) django.db.utils.OperationalError: (1068, 'Multiple primary key defined')
And sure enough the SQL for the backwards migration looks like this (python manage.py sqlmigrate --backwards bug 0002
):
BEGIN; -- -- Delete model Two -- CREATE TABLE `bug_two` (`id` integer AUTO_INCREMENT NOT NULL PRIMARY KEY, `foo` integer NOT NULL); -- -- Remove field one from two -- ALTER TABLE `bug_two` ADD COLUMN `one_id` integer NOT NULL PRIMARY KEY; ALTER TABLE `bug_two` ADD CONSTRAINT `bug_two_one_id_2a65406f_fk_bug_one_id` FOREIGN KEY (`one_id`) REFERENCES `bug_one` (`id`); COMMIT;
Change History (1)
comment:1 by , 6 years ago
Resolution: | → fixed |
---|---|
Status: | new → closed |
Type: | Uncategorized → Bug |
Note:
See TracTickets
for help on using tickets.
This is fixed in the upcoming Django 2.2 release by ad82900ad94ed4bbad050b9993373dafbe66b610. The second migration doesn't have a
RemoveField
operation.