Opened 10 years ago

Last modified 9 years ago

#24653 closed Bug

Migrations: Removing a field with foreign key constraint fails — at Version 2

Reported by: László Károlyi Owned by: nobody
Component: Database layer (models, ORM) Version: 1.9
Severity: Normal Keywords: foreign key constraint mysql
Cc: Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by László Károlyi)

Hey,

I have a model that has a foreign key to another model. Let's say I change my mind and want the relation the other way around (the another model having a foreign key to my model), and so I modify the models accordingly, removing the foreign key of my model.

This creates a migration with a migrations.RemoveField on the model, which is just right. But when running this migration on MySQL, I get an error saying

django.db.utils.OperationalError: (1553, "Cannot drop index 'base_comment_f6be1d8d': needed in a foreign key constraint")

and the migration fails.

Shouldn't the migrations.RemoveField drop that constraint automatically?

This happens using python 3, might have to do something with #24390.

The only way to workaround this now is to create a migrations.RunPython(fk_remove) statement before the migrations.RemoveField, to remove the foreign key manually, by getting its name from INFORMATION_SCHEMA:

def remove_fk(apps, schema_editor):
    from django.db.backends.mysql.base import DatabaseWrapper
    if isinstance(schema_editor.connection, DatabaseWrapper):
        cursor = schema_editor.connection.cursor()
        Edit = apps.get_model('base', 'Edit')
        table_edit_name = Edit._meta.db_table
        cursor.execute('SELECT DATABASE()')
        db_name = cursor.fetchall()[0][0]
        cursor.execute(
            'SELECT CONSTRAINT_NAME FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE'
            ' `TABLE_SCHEMA`=\'%s\' AND `REFERENCED_TABLE_NAME`=\'%s\'' % (
                db_name,
                table_edit_name
            ))
        result = cursor.fetchall()
        if not result:
            return

        Comment = apps.get_model('base', 'Comment')
        table_comment_name = Comment._meta.db_table
        fk_name = result[0][0]
        query = 'ALTER TABLE `%s` DROP FOREIGN KEY `%s`' % (
            table_comment_name,
            fk_name
        )
        cursor.execute(query)

Change History (2)

comment:1 by László Károlyi, 10 years ago

Description: modified (diff)

comment:2 by László Károlyi, 10 years ago

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