[Fixed]-Django 1.9 drop foreign key in migration

22👍

This is how I managed to do it, it’s based on nimasmi’s answer above:

class Migration(migrations.Migration):
    dependencies = [
        ('my_app', '0001_initial'),
    ]

    # These *WILL* impact the database!
    database_operations = [
        migrations.AlterField(
            model_name='Example',
            name='something',
            field=models.ForeignKey('Something', db_constraint=False, db_index=True, null=False)
        ),
    ]

    # These *WON'T* impact the database, they update Django state *ONLY*!
    state_operations = [
        migrations.AlterField(
            model_name='Example',
            name='something',
            field=models.IntegerField(db_index=True, null=False)
        ),
        migrations.RenameField(
            model_name='Example',
            old_name='something',
            new_name='something_id'
        ),
    ]

    operations = [
        migrations.SeparateDatabaseAndState(
            database_operations=database_operations,
            state_operations=state_operations
        )
    ]
👤J. Doe

8👍

See SeparateDatabaseAndState. It allows you to specify a Django (state) part of the migration separately from the database
part of the migration.

  1. Amend the field in your models file.
  2. Create the migration, as normal. You will end up with something like:

    class Migration(migrations.Migration):
    
        dependencies = [
            ('my_app', '0001_whatever.py'),
        ]
    
        operations = [
            migrations.AlterField(
                model_name='example',
                name='something',
                field=models.CharField(max_length=255, null=True)),
            ),
        ]
    
  3. Now manually amend this to:

    class Migration(migrations.Migration):
    
        dependencies = [
            ('my_app', '0001_whatever.py'),
        ]
    
        state_operations = [
            migrations.AlterField(
                model_name='example',
                name='something',
                field=models.CharField(max_length=255, null=True)),
            ),
        ]
        operations = [
            migrations.SeparateDatabaseAndState(state_operations=state_operations)
        ]
    

Note that you are not specifying any database_operations argument, so the Django relationships are amended, but the database data is unchanged.

Needless to say: take a backup before you try this.

5👍

As of Django 2.0, changing your field to models.ForeignKey(db_constraint=False, db_index=False, ...) will generate a migration that does ALTER TABLE DROP CONSTRAINT and DROP INDEX IF EXISTS, which appears to be exactly what you want.

👤btown

Leave a comment