[Django]-How should I upgrade from bradjasper's django-jsonfield to Django's built-in jsonfield?

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:

  1. Add the new Postgres JSON field named json_new.
  2. Make migrations. Do NOT migrate yet.
  3. Dive into the migration file and write a data migration (RunPython) to populate the new json field.
  4. Make migrations.
  5. Delete the old field. Delete the old import.
  6. Make migrations, migrate.
  7. Rename new field to old field name. json_new > json.
  8. Make migrations, migrate.
  9. 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.

Leave a comment