Migrating from TextField to JSONField with Postgres 9.4+ doesn't work

Issue #54 closed
Raphaël Hertzog
created an issue

Create a model with a TextField. Create the initial migration. Then replace that field with a JSONField. Create a new migration.

When you try to apply that migration you will get an error like this:

Running migrations:
  Rendering model states... DONE
  Applying payment_form.0001_squashed_0009_auto_20160622_1911...Traceback (most recent call last):
  File "./manage.py", line 10, in <module>
    execute_from_command_line(sys.argv)
  File "/usr/lib/python2.7/dist-packages/django/core/management/__init__.py", line 354, in execute_from_command_line
    utility.execute()
  File "/usr/lib/python2.7/dist-packages/django/core/management/__init__.py", line 346, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 394, in run_from_argv
    self.execute(*args, **cmd_options)
  File "/usr/lib/python2.7/dist-packages/django/core/management/base.py", line 445, in execute
    output = self.handle(*args, **options)
  File "/usr/lib/python2.7/dist-packages/django/core/management/commands/migrate.py", line 222, in handle
    executor.migrate(targets, plan, fake=fake, fake_initial=fake_initial)
  File "/usr/lib/python2.7/dist-packages/django/db/migrations/executor.py", line 110, in migrate
    self.apply_migration(states[migration], migration, fake=fake, fake_initial=fake_initial)
  File "/usr/lib/python2.7/dist-packages/django/db/migrations/executor.py", line 148, in apply_migration
    state = migration.apply(state, schema_editor)
  File "/usr/lib/python2.7/dist-packages/django/db/migrations/migration.py", line 115, in apply
    operation.database_forwards(self.app_label, schema_editor, old_state, project_state)
  File "/usr/lib/python2.7/dist-packages/django/db/migrations/operations/fields.py", line 201, in database_forwards
    schema_editor.alter_field(from_model, from_field, to_field)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/base/schema.py", line 484, in alter_field
    old_db_params, new_db_params, strict)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/postgresql_psycopg2/schema.py", line 107, in _alter_field
    new_db_params, strict,
  File "/usr/lib/python2.7/dist-packages/django/db/backends/base/schema.py", line 636, in _alter_field
    params,
  File "/usr/lib/python2.7/dist-packages/django/db/backends/base/schema.py", line 111, in execute
    cursor.execute(sql, params)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
  File "/usr/lib/python2.7/dist-packages/django/db/utils.py", line 100, in __exit__
    six.reraise(dj_exc_type, dj_exc_value, traceback)
  File "/usr/lib/python2.7/dist-packages/django/db/backends/utils.py", line 64, in execute
    return self.cursor.execute(sql, params)
django.db.utils.ProgrammingError: column "raw_data" cannot be cast automatically to type jsonb
HINT:  You might need to specify "USING raw_data::jsonb".

Then, as a test, I changed JSONField.db_type() to never return "jsonb" and the migration completed successfully...

Comments (3)

  1. Ben Finney

    This seems like a common requirement, with many ways to get it wrong, and (probably) one good way to do it right that will work for most people.

    Do you think such a migration is best written once and distributed as part of the code base that implements JSONField?

    (Putting aside for the moment who will do the work of implementing it.)

  2. Log in to comment