Django Migrate from Char Field to Integer Field?

Viewed 3433

I changed one of my CharField in models.py::

models.CharField(max_length=128, blank=True)

into IntegerField -->

models.IntegerField(default=0)

I have data for that field, mainly empty strings("") or integer as strings(eg: "10").

So I would like to convert these strings to integer while migrate. eg:: if blank string("") convert to 0, else convert to integer.

How can i achive that while i do ./manage.py migrate command?

here is the migration file created using ./manage.py makemigrations::

# Generated by Django 2.1.2 on 2018-10-25 04:57

from django.db import migrations, models


class Migration(migrations.Migration):

    dependencies = [
        ('dashboard', '0002_auto_20181024_1544'),
    ]

    operations = [
        migrations.AlterField(
            model_name='aclpermissions',
            name='ordering',
            field=models.IntegerField(default=0),
        ),
        migrations.AlterField(
            model_name='submenus',
            name='ordering',
            field=models.IntegerField(default=0),
        ),
        migrations.AlterField(
            model_name='subsubmenus',
            name='ordering',
            field=models.IntegerField(default=0),
        ),
    ]

When i run ./manage.py migrate i got error ::

psycopg2.DataError: invalid input syntax for integer: ""

because there are fields with empty strings "".

So I want to convert empty strings ("") to 0.

3 Answers

For others coming upon this, you can add a function to run before the other migration operations:

class Migration(migrations.Migration):

    def blank_to_zero(apps, schema_editor):
        AclPermissions = apps.get_model('dashboard', 'AclPermissions')
        SubMenus = apps.get_model('dashboard', 'SubMenus')
        SubSubMenus = apps.get_model('dashboard', 'SubSubMenus')

        for obj in AclPermissions.objects.filter(ordering=''):
            obj.ordering = 0
            obj.save()

        for obj in SubMenus.objects.filter(ordering=''):
            obj.ordering = 0
            obj.save()

        for obj in SubSubMenus.objects.filter(ordering=''):
            obj.ordering = 0
            obj.save()

    dependencies = [
        ('dashboard', '0002_auto_20181024_1544'),
    ]

    operations = [
        migrations.RunPython(blank_to_zero),

        migrations.AlterField(... 
        # the rest of your operations
    ]

See https://docs.djangoproject.com/en/dev/topics/migrations/#data-migrations for info on editing data migrations.

Change AlterField in your migration to RemoveField and then AddField -> note that this will drop your existing data!

    migrations.RemoveField(
        model_name='aclpermissions',
        name='ordering',
    ),
    migrations.AddField(
        model_name='aclpermissions',
        name='ordering',
        field=models.IntegerField(default=0),
    ),

Char/OLD:

email_type = models.CharField(max_length=50, default=None)

Change it to Int/New:

email_type = models.IntegerField(default=None)
  • python manage.py makemigration

Way to Change:

  1. By losing data(Easy way)

Revert migration to previous version

  1. Without losing Data (Harder way)

Open Python shell or Write a script to -- chanage each values of 'email_type' to numbers (like 0, 1, 2, 3...)

And then

  • python manage.py migrate
Related