Django Migrations

After creating or updating a model in models.py, the changes do not automatically reflect in the database. You need to run migrations to sync your models with the actual database. Think of migrations as the bridge between your Python code and your database.

What is a Migration?

A migration is a file that Django generates automatically based on the changes you make to your models. It contains instructions on how to create or modify database tables. Django reads these files and applies them to the database when you tell it to.

Example: Imagine you are renovating a house. First, you draw a plan (model change). Then you hand the plan to the construction team (migration file). The team then builds the actual changes to the house (database). Without giving them the plan, the house stays the same no matter what you drew.

Two-Step Migration Process

Every time you create or change a model, you follow two steps:

Step 1 — makemigrations

This command reads your models.py and generates a new migration file inside the migrations/ folder. It does NOT touch the database yet — it only creates the plan.


python manage.py makemigrations

You will see output like:


Migrations for 'school':
  school/migrations/0001_initial.py
    - Create model Student

Step 2 — migrate

This command reads all pending migration files and applies them to the actual database, creating or modifying tables.


python manage.py migrate

You will see output like:


Operations to perform:
  Apply all migrations: admin, auth, contenttypes, school, sessions
Running migrations:
  Applying school.0001_initial... OK
Example: makemigrations is like writing a recipe. migrate is like actually cooking the dish. Writing the recipe does nothing to your hunger — you have to cook it to get the food.

Understanding the migrations/ Folder

After running makemigrations, Django creates numbered files inside the migrations/ folder:


school/
└── migrations/
    ├── __init__.py
    ├── 0001_initial.py        <-- First migration: creates the Student table
    ├── 0002_student_phone.py  <-- Second migration: adds a phone column
    └── 0003_alter_student...  <-- Third migration: modifies something

Each file is numbered in order. Django tracks which migrations have been applied so it only runs the new ones each time you run migrate.

Checking Migration Status

To see which migrations have been applied and which are still pending, use:


python manage.py showmigrations

Output example:


school
 [X] 0001_initial          <-- [X] means applied
 [ ] 0002_student_phone     <-- [ ] means NOT applied yet

What Happens When You Change a Model?

Let us say you created the Student model with name, age, and email fields. Later you want to add a phone field. Here is the process:

1. Update models.py


class Student(models.Model):
    name = models.CharField(max_length=100)
    age = models.IntegerField()
    email = models.EmailField(unique=True)
    phone = models.CharField(max_length=15, blank=True, null=True)  # <-- New field

2. Run makemigrations


python manage.py makemigrations

Django detects the new field and creates:


Migrations for 'school':
  school/migrations/0002_student_phone.py
    - Add field phone to student

3. Run migrate


python manage.py migrate

Django adds the phone column to the school_student table in the database.

Example: Think of your school's student registration form. Originally it had Name, Age, and Email. Later the school decided to also collect Phone Number. They printed a new updated form (migration file) and updated all existing records in their register (database).

Makemigrations for a Specific App

If you have multiple apps, you can run makemigrations for just one specific app:


python manage.py makemigrations school

Viewing What a Migration Will Do

Before applying a migration, you can preview the SQL commands it will execute on the database:


python manage.py sqlmigrate school 0001

This shows the raw SQL like:


BEGIN;
CREATE TABLE "school_student" (
    "id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
    "name" varchar(100) NOT NULL,
    "age" integer NOT NULL,
    "email" varchar(254) NOT NULL UNIQUE
);
COMMIT;
Example: It is like reading through a building permit before the construction starts. You can review exactly what will be built before giving the final go-ahead.

Common Migration Mistakes and Fixes

Forgot to run makemigrations before migrate

If you changed your model but forgot to run makemigrations, the changes will not be saved into a migration file and migrate will not apply them. Always run both commands in order.

Adding a new required field to an existing model

If you add a field without null=True or default=value, Django will ask you what to do with existing rows that have no value for this new field. Always provide a default or allow null for new required fields on existing tables.


# Safe way to add a new field to an existing table
phone = models.CharField(max_length=15, blank=True, null=True)
# or
phone = models.CharField(max_length=15, default='')

Quick Recap


# Step 1: After creating or editing models.py, generate the migration file
python manage.py makemigrations

# Step 2: Apply the migration to the database
python manage.py migrate

# Check which migrations are applied
python manage.py showmigrations

# Preview the SQL for a specific migration
python manage.py sqlmigrate school 0001

Leave a Comment

Your email address will not be published. Required fields are marked *