[Fixed]-How to rename a foreignkey field with South?

4👍

Update: with mysql-5.5.30-1.fc18.x86_64 and

MySQL-python==1.2.4
Django==1.4.2
South==0.7.6

the following works:

class Migration(SchemaMigration_:
    def forwards(self, orm):
        db.rename_column('app_model', 'old_id', 'new_id')
        db.alter_column('app_model', 'new_id',
                        self.gf('django.db.models.fields.related.ForeignKey')(
                            blank=True,
                            null=True,
                            to=orm['app.OtherModel']
                        ))

    def backwards(self, orm):
        db.rename_column('app_model', 'new_id', 'old_id')
        db.alter_column('app_model', 'old_id',
                        self.gf('django.db.models.fields.related.ForeignKey')(
                            blank=True,
                            null=True,
                            to=orm['app.OtherModel']
                        ))

As @Eloff comments, South can’t find the original FK for reasons unknown, but it doesn’t seem to matter. There is no need for a data migration (I believe) as pk values should not change.

The field specification (using self.gf) is taken from South’s auto-generated migrations for consistency.

24👍

First, you need to use the db column name not the one in the model. Eg: foobar_id not foobar.

Then you need to drop the fk constraints and recreate them after renaming:

db.drop_foreign_key('app_model', 'old_id')
db.rename_column('app_model', 'old_id', 'new_id')
db.alter_column('app_model', 'new_id', models.ForeignKey(to=orm['app.OtherModel']))

If your fk is nullable you need to use change it to:

db.alter_column('app_model', 'new_id', models.ForeignKey(null=True, to=orm['app.OtherModel']))

11👍

MySQL users ought to be aware of this bug in south, if indeed it still applies:

http://south.aeracode.org/ticket/697

The workaround is to conduct the migration in 3 steps:

1) Add new field

2) data migrate the data to the new field

3) delete the old field

👤Yeago

6👍

When renaming a ForeignKey, remember to add _id to the end of the field name you use in Django. E.g.

db.rename_column('accounts_transaction', 'operator_id', 'responsible_id')

And not

db.rename_column('accounts_transaction', 'operator', 'responsible')

But I have only tested this on sqlite (which don’t actually have the ALTER_TABLE at all), so I don’t know if it will actually work on mysql/postgres.

Leave a comment