Add Migration Nonnull Foreignkey Field Django

Published on 1 August 2022 12:00 AM
This post thumbnail

Provide a one-off default now (will be set on all existing rows with a null value for this column)

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?

Resource:

https://jaketrent.com/post/add-migration-nonnull-foreignkey-field-django