Add a Migration for a Non-null ForeignKey Field in Django
Here's a method for getting that new foreign key column to be non-nullable and without a default.
Django migrations are awesome
Django has a solid ORM and some nice database migrations to go with it. First, make a change to your model in python code, then run:
python manage.py makemigrations
The the migrations will be generated based on your model changes since the last migration. To apply the migrations in the database, run:
python manage.py migrate
But what if you want to make a migration for a new non-nullable field?
Protective parent
Well, Django wants to help you do the right thing. And if you add a new non-nullable field to the model and run makemigrations
, it'll balk and warn you that you can't make a new non-null field because you might already have rows without that new column, and those rows can't violate the non-null constraint on the column.
It'll report something like:
~/myapp ❯ python manage.py makemigrations
You are trying to add a non-nullable field 'created_by' to mymodel without a default; we can't do that (the database needs something to populate existing rows).
Please select a fix:
1) Provide a one-off default now (will be set on all existing rows with a null value for this column)
2) Quit, and let me add a default in models.py
Give in and add the default
To get the migrations to run, add the default one way or the other.
That might look like:
from django.contrib.auth.models import User
from django.db import models
class MyModel(models.Model):
# ...
created_by = models.ForeignKey(User, default="")
Now you'll be able to makemigrations
.
Then turn around and remove it
But now you're sneaking out the bedroom window...
Adjust your model again, removing the default:
from django.contrib.auth.models import User
from django.db import models
class MyModel(models.Model):
# ...
created_by = models.ForeignKey(User)
You run makemigrations
again, and you're set: new column, no default, non-nullable.
A bit of a run-around? Yes. Do you have a better way to do this?