My app that currently depends on Postgres and Django's Postgres-only JSONField
. The field works well and I've no interest in another project, but I have prospective-users who want to use my app, but can't while it relies on Postgres.
Django 3.1 has a cross-platform version of this field —which will work for my needs— but I don't want to force everybody up to Django 3.1; I would like to offer people a choice between Postgres or Django 3.1+. On paper, this is simple enough with a conditional import...
try:
from django.db.models import JSONField
except ImportError:
from django.contrib.postgres.fields import JSONField
And if I installed Django 3.1 and generated a migration, it could take me from django.contrib.postgres.fields.JSONField
to django.db.models.JSONField
. But...
This is worse than when I started. How do I do this sort of field migration in a way that will work for everybody?
To answer your question, with the new migration introduced in Django 1.7, in order to add a new field to a model you can simply add that field to your model and initialize migrations with ./manage.py makemigrations and then run ./manage.py migrate and the new field will be added to your DB. Save this answer.
you can either: temporarily remove your migration, execute python manage.py migrate, add again your migration and re-execute python manage.py migrate. Use this case if the migrations refer to different models and you want different migration files for each one of them.
migrate , which is responsible for applying and unapplying migrations. makemigrations , which is responsible for creating new migrations based on the changes you have made to your models.
All new migrations will be correct automatically if this solution with a deconstruct() method will be used.
You can create a compatible custom JSONField that encapsulates both variants.
Create a small file fields.py
in your application:
try:
from django.db.models import JSONField as OrigJSONField
except ImportError:
from django.contrib.postgres.fields import JSONField as OrigJSONField
class JSONField(OrigJSONField):
def deconstruct(self):
# the original path was 'django.db.models.JSONField' or 'django.contrib.postgres.fields....'
name, path, args, kwargs = super().deconstruct()
# Substitute 'my_app' by your application name everywhere.
path = 'my_app.fields.JSONField'
return name, path, args, kwargs
Change a line in your models.py
:
from my_app.fields import JSONField
Edit all existing migrations that use a JSONField:
import my_app.fields
...
('stuff', my_app.fields.JSONField()),
(or equivalently)
from my_app.fields import JSONField
...
('stuff', JSONField()).
No migration is created after that because no difference is found by makemigrations.
All future makemigrations
after a changed model will be created automatically with my_app.fields.JSONField()
. Compatibility is a benefit of this solution.
Reflection about Django Release Notes 3.1 and future:
They describe a plain upgrade that requires to create a new migration that only upgrades the import path, but it generates no SQL e.g. by sqlmigrate
. It is easier than to edit old migrations.
Maybe you you also upgrade in two years to Django >= 3.1 only and you will have two alternatives:
A) Only the import in models.py
will be edited and you create a new nearly empty formal migration similarly to release notes. You will be not able to remove the import path my_app.fields.JSONField
because it must be importable from old migrations similarly that Django can never remove the path django.contrib.postgres.fields.JSONField
. The file my_app/fields.py
could be simplified to one line from django.db.models import JSONField as JSONField
after an unconditional upgrade of requirements.
B) Editing old migrations again to only the new JSONField is possible, but unreasonable.
(It is every user's responsibility that an edit in a migrations file doesn't require a changed database state and all migrations remain consistent each other. That is why not much about it can be found, except such clear cases.)
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