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?
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.
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.
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.
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.
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.
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With