5

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.

suhailvs
  • 20,182
  • 14
  • 100
  • 98
  • You changed one of my CharFields to an IntegerField. Which one? Your migration file show that you changed 3 fields. – Red Cricket Oct 26 '18 at 04:23
  • 1
    @RedCricket i change 3 charfields to integerfield. i solved the problem by updating all the `empty strings` in db to `0`. now the `./manage.py migrate` command worked fine. – suhailvs Oct 26 '18 at 04:34
  • do you mean you updated all the empty values to the string "0"? – Red Cricket Oct 26 '18 at 04:52
  • 1
    @RedCricket yes. after update i run `./manage.py migrate` which worked. – suhailvs Oct 26 '18 at 05:02
  • 2
    I would first create 3 new fields and write a [data migration](https://docs.djangoproject.com/en/dev/topics/migrations/#data-migrations), then run a second migration that renames those 3 fields back. – Selcuk Oct 26 '18 at 05:05
  • @Selcuk I think creating new fields are not required since `migrate` command will do that job. – suhailvs Oct 26 '18 at 05:43

3 Answers3

2

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.

Webucator
  • 2,397
  • 24
  • 39
  • 1
    Reduce to a single query per model: `AclPermissions.objects.filter(ordering='').update(ordering=0)`. Will save a lot of time if there are many objects. – Huon Jan 12 '21 at 23:15
1

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),
    ),
Georgi
  • 11
  • 1
-1

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
tghw
  • 25,208
  • 13
  • 70
  • 96
Amrit Prasad
  • 373
  • 6
  • 18