Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django + South - migration can't cast the column type - wants me to use "USING"

I'm getting this error when I try to run ./manage.py migrate my_app:

django.db.utils.ProgrammingError: column "associated" cannot be cast automatically to type integer
HINT: Specify a USING expression to perform the conversion.

That sounds like great advice, but I don't know exactly what South wants me to do. Am I supposed to manually edit the auto-generated python migration file? If so, how -- I don't see standard SQL in that file. Instead, I see this:

# Changing field 'MyTable.associated'
db.alter_column(u'data_mytable', 'associated', 
    self.gf('django.db.models.fields.IntegerField')()
)

Also, why didn't South pick up on this and add the USING clause automatically?

like image 933
tadasajon Avatar asked Mar 10 '14 21:03

tadasajon


People also ask

What is South migration in Django?

South is a migration tool used with Django. There will be times when you would be adding fields to a model or changing the type of field (eg: Field was an IntegerField and you want to change it to FloatField). In such cases syncdb doesn't help and South comes to your rescue.

Which command is used for migration in Django?

The Commands There are several commands which you will use to interact with migrations and Django's handling of database schema: migrate , which is responsible for applying and unapplying migrations. makemigrations , which is responsible for creating new migrations based on the changes you have made to your models.


2 Answers

This was my dirty hack:

  1. Manually added a migraton for removing the offendig field i.e

migrations.RemoveField( model_name='name_of_the_model', name='offending_field', ) 2. Then I changed the operation of the complaining migration from AlterField to AddField i.e

migrations.AddField(
        model_name='name_of_model',
        name='name_of_field',
        field=models.ForeignKey(blank=True, null=True, to='ForeignKeyModel'),
        preserve_default=False,
    ),

```

like image 120
Liyosi Avatar answered Oct 13 '22 02:10

Liyosi


You have to substitute original db.alter_column with a db.execute:

# Changing field 'MyTable.associated'
# db.alter_column(u'data_mytable', 'associated', 
#     self.gf('django.db.models.fields.IntegerField')()
# )
db.execute(
    'ALTER TABLE "data_mytable" '
    'ALTER COLUMN "associated" DROP DEFAULT, '
    'ALTER COLUMN "associated" DROP NOT NULL, '
    'ALTER COLUMN "associated" TYPE INTEGER '
    'USING '
    'CASE '
    '  WHEN FALSE THEN 0 ELSE 1 '
    'END'
) 

Of course, WHEN condition may change depending of the associated original type.
See also this link.

like image 21
Salvatore Avanzo Avatar answered Oct 13 '22 01:10

Salvatore Avanzo