Migrations

Migrations are Django’s way of handling database schema changes. They allow you to create, modify, and delete database tables and fields without losing data.
Author

Benedict Thekkel

🔹 1. Understanding Migrations

Migrations are: - Auto-generated files that store changes to your models. - Applied to the database to create/update/delete tables and fields. - Version-controlled so changes can be tracked over time.

They ensure consistency between the database and Django models.


🔹 2. Key Migration Commands

Command Description
python manage.py makemigrations Generates migration files based on model changes.
python manage.py migrate Applies migrations to the database.
python manage.py showmigrations Displays a list of applied and unapplied migrations.
python manage.py sqlmigrate <app_name> <migration_number> Shows the raw SQL that will be executed for a migration.
python manage.py migrate <app_name> zero Rolls back all migrations for an app.
python manage.py makemigrations --dry-run Shows what migrations will be created without making changes.
python manage.py migrate --fake-initial Marks initial migrations as applied without actually running them.

🔹 3. How Migrations Work

Step 1: Create a Model

from django.db import models

class Product(models.Model):
    name = models.CharField(max_length=255)
    price = models.DecimalField(max_digits=10, decimal_places=2)
    created_at = models.DateTimeField(auto_now_add=True)

Run:

python manage.py makemigrations

This creates a migration file, e.g., 0001_initial.py, inside migrations/.


Step 2: Apply the Migration

python manage.py migrate

Django creates the corresponding SQL table.

To see the SQL executed:

python manage.py sqlmigrate <app_name> 0001

🔹 4. Common Migration Operations

🛠 Adding a New Field

Add a category field to the Product model:

category = models.CharField(max_length=100, default="General")

Run:

python manage.py makemigrations
python manage.py migrate

✅ The field is added without losing existing data.


🛠 Renaming a Field

Change name to title:

class Product(models.Model):
    title = models.CharField(max_length=255)  # Renamed

Django automatically detects this change and creates a migration.


🛠 Removing a Field

Delete the category field:

class Product(models.Model):
    title = models.CharField(max_length=255)

Run:

python manage.py makemigrations
python manage.py migrate

✅ Django removes the column from the database.


🛠 Changing Field Type

Change price from DecimalField to IntegerField:

price = models.IntegerField()

Django will warn if data conversion might cause data loss.


🛠 Creating a New Model

Add an Order model:

class Order(models.Model):
    product = models.ForeignKey(Product, on_delete=models.CASCADE)
    quantity = models.IntegerField()
    order_date = models.DateTimeField(auto_now_add=True)

Run:

python manage.py makemigrations
python manage.py migrate

✅ Django creates a new table in the database.


🔹 5. Rolling Back Migrations

Undo the Last Migration

python manage.py migrate <app_name> <previous_migration_number>

🔹 Example: If the latest migration is 0003_auto, roll back to 0002:

python manage.py migrate product 0002

Undo All Migrations for an App

python manage.py migrate <app_name> zero

🔹 Example:

python manage.py migrate product zero

This removes all tables for product but does not delete migration files.


🔹 6. Handling Migration Issues

🛑 Missing Migrations Error

If Django detects model changes but no migrations were created, run:

python manage.py makemigrations
python manage.py migrate

🛑 “Table already exists” Error

This happens when Django tries to create a table that already exists.

🔹 Fix: Fake the initial migration:

python manage.py migrate <app_name> --fake-initial

🛑 Foreign Key Constraint Error

This happens if a related model does not exist.

🔹 Fix: Ensure the related model has been migrated first:

python manage.py migrate <related_app>

🛑 Reverse a Corrupt Migration

If a migration was applied incorrectly:

python manage.py migrate <app_name> <previous_migration>

🔹 Example:

python manage.py migrate product 0001

Then delete the incorrect migration file and re-run:

python manage.py makemigrations
python manage.py migrate

🔹 7. Deleting Migrations and Starting Fresh

⚠️ This is destructive and removes all migration history.

Step 1: Delete Migration Files

find . -path "*/migrations/*.py" -not -name "__init__.py" -delete

Step 2: Reset the Database

python manage.py flush

This deletes all database records but keeps tables.

Step 3: Recreate Migrations

python manage.py makemigrations
python manage.py migrate

✅ Now your project has a clean migration history.


🔹 8. Migrating Models to Another App (Without Data Loss)

If you move a model from app_a to app_b, follow these steps:

Step 1: Add db_table in the New Model

class MyModel(models.Model):
    class Meta:
        db_table = "app_a_mymodel"

Step 2: Fake the Migration

Run:

python manage.py makemigrations app_b
python manage.py migrate app_b --fake-initial

The database remains unchanged, but Django recognizes the model in the new app.


🔹 9. Best Practices

Always Commit Migration Files – Never ignore migrations in version control.
Use --dry-run Before Applying Changes – Run: bash python manage.py makemigrations --dry-runKeep Migrations Linear – Don’t edit old migration files unless necessary.
Use --fake-initial When Moving Models – Prevents Django from recreating tables.
Backup Before Major Changes – Always use: bash python manage.py dumpdata > backup.json


🎯 Summary of Key Migration Commands

Command Action
makemigrations Create migration files
migrate Apply migrations to the database
showmigrations List applied and unapplied migrations
sqlmigrate <app> <num> Show SQL for a migration
migrate <app> zero Roll back all migrations for an app
migrate --fake-initial Mark migrations as applied without running them
flush Reset database (delete all data)

Back to top