4👍
The ALTER COLUMN command from @tometzky via Upgrade PostgreSQL JSON column to JSONB?
does this with surprisingly little hassle:
- sudo -u postgres psql -c ‘ALTER TABLE mytable ALTER COLUMN “myfield” TYPE jsonb USING “myfield”::text::jsonb;’ mydatabase
I didn’t need Django’s loaddata / dumpdata commands or a custom migration.
I did have some issues getting pg_upgrade to work the way I wanted, since it wasn’t on the default path and wanted to change the port used by Postgres during the upgrade. To get around that, I did the following:
- pg_ctl -D /etc/postgresql/9.4/main/ stop
- use
sed
on postgresql.conf to change which port it used - install Postgres 9.6
- pg_ctl -D /etc/postgresql/9.6/main/ stop
- cd /var/log/postgresql
- run pg_upgrade
- cd back to the original working directory
- apt-get -y remove postgresql-9.4 postgresql-client-9.4 postgresql-server-dev-9.4
- service postgresql start
11👍
Upgrade Postgres first. If all works upgrade Django.
Only if everything works as expected you can start writing your field migration.
You want to go from:
from jsonfield import JSONField
class MyModel(models.Model):
json = JSONField()
To:
from django.contrib.postgres.fields import JSONField
class MyModel(models.Model):
json = JSONField()
Steps:
- Add the new Postgres JSON field named
json_new
. - Make migrations. Do NOT migrate yet.
- Dive into the migration file and write a data migration (RunPython) to populate the new json field.
- Make migrations.
- Delete the old field. Delete the old import.
- Make migrations, migrate.
- Rename new field to old field name.
json_new
>json
. - Make migrations, migrate.
- Done.
Step 1:
Use import ... as ...
to prevent collisions. Your model will look like:
from jsonfield import JSONField as OldJSONField
from django.contrib.postgres.fields import JSONField
class MyModel(models.Model):
json = OldJSONField()
json_new = JSONField()
Step 3:
You need to RunPython
in your migration see https://docs.djangoproject.com/en/1.10/ref/migration-operations/#runpython
Also note how to import your model.
The actual data migration will be something like:
for obj in MyModel.objects.all()
obj.json_new = obj.json
obj.save()
Step 4 – 7:
Make sure you create separate migrations for deleting and renaming. If you do all code changes and create a single migration, then Django will think you dropped json_new
. But you want to drop json
and rename json_new
to json
. Small, but important difference.
It isn’t to hard to reduce the migration steps. But that requires to write some code by hand. I’m lazy and like Django to write this code for me.
- [Django]-Django migration dependency order
- [Django]-Python & Django on a Mac: Illegal hardware instruction
- [Django]-How to modify the app name in Django admin's urls?
- [Django]-Django: can't bind an uploaded image to a form ImageField()