South, how to migrate from CharField to ForeignKey?
Question: The model:

    
    
    class ListContext(models.Model):
        content = models.CharField(max_length=200, blank=True)
    

I use south to manage schema migrations.

Now I change the previous model to this one:

    
    
    from django.contrib.contenttypes.models import ContentType
    
    class ListContext(models.Model):
        content = models.ForeignKey(ContentType, blank=True, null=True)
    

For the migration:

    
    
    $ python manage.py schemamigration --auto page 
     ~ Changed field content on page.ListContext
     + Added index for ['content'] on page.ListContext
    Created 0010_auto__chg_field_listcontext_content.py. You can now apply this migration with: ./manage.py migrate page
    

Everything is fine until this point:

    
    
    $ python manage.py migrate page 
    Running migrations for page:
     - Migrating forwards to 0010_auto__chg_field_listcontext_content.
     > page:0010_auto__chg_field_listcontext_content
    FATAL ERROR - The following SQL query failed: ALTER TABLE "page_page_listcontext" ALTER
    COLUMN "content_id" TYPE integer, ALTER COLUMN "content_id" DROP NOT NULL, ALTER COLUMN
    "content_id" DROP DEFAULT;
    
    The error was: column "content_id" cannot be cast to type integer
    
    Error in migration: page:0010_auto__chg_field_listcontext_content
    

I can guess the error happens during the cast from string to int, but how can
I avoid this and get the migration done?

Could it make any difference, I don't care to preserve the data stored in the
table.


Answer: If you manually edit the forwards function:

Rename the column:

    
    
    db.rename_column('sometable', 'content', 'content_old')
    

Then add your column back:

    
    
    db.add_column('sometable', 'content', self.gf('django.db.models.fields.IntegerField')(default=0))
    

Then execute a query that updates the new field by looking up the id.

    
    
    db.execute("""
      UPDATE sometable SET content =
      (SELECT FKTable.id FROM FKTable
      WHERE (FKTable.content = sometable.content_old AND
      sometable.content_old != '')
      OR (FKTable.content = 'none' AND sometable.content_old = '')) --Maybe cut the OR out
    """)
    

You would then have to do some fancy stuff to make backwards work properly.

