South Migrations foreign key name change

Data migration is confusing. Here are a few south migrations I needed to change the name of a foreign key. For any of this to make sense you need a pretty good understanding of south.

Old model:

class CustomField(models.Model):
    name = models.ForeignKey('CustomFieldName', null=True, blank=True)
    politician = models.ForeignKey(Candidate, null=True, blank=True)

New model:

class CustomField(models.Model):
    name = models.ForeignKey('CustomFieldName', null=True, blank=True)
    candidate = models.ForeignKey(Candidate, null=True, blank=True,help_text='choose a candidate for a field specific to this race or elections')
    politician = models.ForeignKey('legislators.Politician',null=True, blank=True,default=None,help_text='Choose a politician for fields to persist through multiple elections and races')

I was able to do this pretty easily with rename_column()

Now that I had renamed my field to candidate, politician was freed up to use for a new column, or so I thought. I ran a typical schema migration after adding politician and kept getting an error that politician_id already existed. Where was it coming from? South adds an index to the table. I needed to run

db.delete_index('elections_customfield', 'politician_id')

Only after that was I able to re-add politician as a field. Took me a few hours of struggle so I thought I’d write about.

Final migrations:

change name:

    def forwards(self, orm):
        "Write your forwards methods here."
        # Note: Don't use "from appname.models import ModelName". 
        # Use orm.ModelName to refer to models in this application,
        # and orm['appname.ModelName'] for models in other applications.
        db.delete_foreign_key('elections_customfield', 'politician_id')
        db.delete_index('elections_customfield', 'politician_id')
        db.rename_column('elections_customfield', 'politician_id','candidate_id')
        db.alter_column('elections_customfield', 'candidate_id', models.ForeignKey(to=orm['elections.Candidate']))
   
    def backwards(self, orm):
        "Write your backwards methods here."
        db.rename_column('elections_customfield', 'candidate_id','politician_id')

Re-add politician as a differnt field:


    def forwards(self, orm):
        # Adding field 'CustomField.politician'
        db.add_column('elections_customfield', 'politician',
                      self.gf('django.db.models.fields.related.ForeignKey')(default=None, to=orm['legislators.Politician'], null=True, blank=True),
                      keep_default=False)

In my case i needed to migrate the old politician data to the new politician field:

    def forwards(self, orm):
        "Write your forwards methods here."
        # Note: Don't use "from appname.models import ModelName". 
        # Use orm.ModelName to refer to models in this application,
        # and orm['appname.ModelName'] for models in other applications.
        for custom_field in orm.CustomField.objects.all():
            candidate = custom_field.candidate.politician
            custom_field.politician = candidate
            #custom_field.candidate = None
            custom_field.save()

goodbye

Leave a Reply

Your email address will not be published. Required fields are marked *