13

Renaming a simple charfield etc seems easy (Django - How to rename a model field using South?)

However when I try using the same on a ForeignKey field I get an error:

_mysql_exceptions.OperationalError: (1091, "Can't DROP '[new_fkey_field_name]'; check that column/key exists")

Which stems from the migration trying to run the backwards for some reason (as evidenced in the trace).

Any ideas?

Community
  • 1
  • 1
GJ.
  • 5,226
  • 13
  • 59
  • 82
  • Looks like problem is on MySql side. - What storage engine did you use? - Do you use MyISAM(which does not support referential integrity)? - Did you try the it with sqlite of postgresql? – Mir Nazim Aug 15 '10 at 12:25
  • Similar question here: http://stackoverflow.com/questions/1600129/using-south-to-refactor-a-django-model-with-inheritence – viam0Zah May 17 '11 at 13:23

4 Answers4

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']))
Richard J. Ross III
  • 55,009
  • 24
  • 135
  • 201
ionelmc
  • 720
  • 2
  • 10
  • 29
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
  • 111
  • 1
  • 2
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.

J. Steen
  • 15,470
  • 15
  • 56
  • 63
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.

supervacuo
  • 9,072
  • 2
  • 44
  • 61
  • 1
    You might get bitten by [this little South bug](http://south.aeracode.org/ticket/1186) if you use this solution. Either monkey-patch South (see ticket) or bribe [Andrew](http://aeracode.org) to fix it – supervacuo Jun 14 '13 at 13:43