Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django change database field from integer to CharField

I have a Django app with a populated (Postgres) database that has an integer field that I need to change to a CharField. I need to start storing data with leading zeros in this field. If I run migrate (Django 1.8.4), I get the following error:

psycopg2.ProgrammingError: operator does not exist: character varying >= integer

HINT: No operator matches the given name and argument type(s). You might need to add explicit type casts.

I tried searching Google, but didn't really find much help. I don't really know what I'm supposed to do here. Can anyone help?

like image 630
mpsg Avatar asked Oct 29 '15 01:10

mpsg


People also ask

Which Django model fields is used for integer value?

IntegerField is a integer number represented in Python by a int instance. This field is generally used to store integer numbers in the database. The default form widget for this field is a NumberInput when localize is False or TextInput otherwise.

What is AutoField in Django?

According to documentation, An AutoField is an IntegerField that automatically increments according to available IDs. One usually won't need to use this directly because a primary key field will automatically be added to your model if you don't specify otherwise.

What is null True in Django?

null = True. Means there is no constraint of database for the field to be filled, so you can have an object with null value for the filled that has this option. blank = True. Means there is no constraint of validation in django forms.

How do you use model choices in Django?

Django field choices are sequences consisting of iterables of exactly two items (e.g. [(A, B), (C, D) ...]) to use as choices for some field. If the choices are provided, they're enforced by model validation. The default form widget will be a select box with specified choices, not the standard text field.


2 Answers

Originally, I thought that there would be a simple solution where Django or Postgres would do the conversion automatically, but it appears that it doesn't work that way. I think some of suggestions made by others might have worked, but I came up with a simple solution of my own. This was done on a production database so I had to be careful. I ended up adding the character field to the model and did the migration. I then ran a small script in the python shell that copied the data in the integer field, did the conversion that I needed, then wrote that to the new field in the same record in the production database.

for example:

members = Members.objects.all()
for mem in members:
    mem.memNumStr = str(mem.memNum)
    ... more data processing here
    mem.save()

So now, I had the data duplicated in the table in a str field and an int field. I could then modify the views that accessed that field and test it on the production database without breaking the old code. Once that is done, I can drop the old int field. A little bit involved, but pretty simple in the end.

like image 151
mpsg Avatar answered Oct 22 '22 03:10

mpsg


You'll need to generate a schema migration. How you do that will depend on which version of Django you are using (versions 1.7 and newer have built-in migrations; older versions of Django will use south).

Of Note: if this data is production data, you'll want to be very careful with how you proceed. Make sure you have a known good copy of your data you can reinstall if things get hairy. Test your migrations in a non-production environment. Be. Careful!

As for the transformation on the field (from IntegerField to CharField) and the transformation on the field values (to be prepended with leading zeroes) - Django cannot do this for you, you'll have to write this manually. The proper way to do this is to use the django.db.migrations.RunPython migration command (see here).

My advice would be to generate multiple migrations; one that creates a new IntegerField, my_new_column and then write to this new column via RunPython. Then, run a second migration that removes the original CharField my_old_column and renames my_new_column as my_old_column.

like image 20
chucksmash Avatar answered Oct 22 '22 04:10

chucksmash