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?
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
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)
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?