Skip to content

Django Migrations

We have a model created now, but the database has no tables to store it.

Django's migration tool is built-in, and each app keeps its migrations in a migrations/ folder next to its models.

A migration is generated and then applied: makemigrations writes the file, and migrate runs it.

Generate Migrations with makemigrations

Now we'll generate a migration for Animal:

shell
uv run manage.py makemigrations
Text
Migrations for 'animals':
  animals/migrations/0001_initial.py
    + Create model Animal

The accounts app's migration, for our user model, came with the starting branch.

Review the Migration

It's a best practice to look at a generated migration after creating it, before applying it to the database. Ours for Animal is in animals/migrations/0001_initial.py, if you want to read it.

Apply Migrations with migrate

Now we'll apply our migrations:

shell
uv run manage.py migrate

The output also lists the migrations of the built-in apps startproject installed.

Committing Migrations

Migration files are part of our code, so we commit each one together with the model change it came from. When a teammate pulls that commit, or a server deploys it, migrate applies the same change to their database. Every copy ends up with the same tables.

How do I undo a migration?

Run migrate with the app's name and the migration just before the one you want to undo. Once animals has a 0002 migration, this unapplies 0002:

shell
uv run manage.py migrate animals 0001

Unapplying a migration leaves its file in migrations/, so the next migrate would apply it again. To replace the migration with a new one:

shell
uv run manage.py migrate animals 0001
rm animals/migrations/0002_*.py
uv run manage.py makemigrations

uv run manage.py migrate animals zero unapplies every migration in the app.