Skip to main content

Django Database Migration

When developing Django applications, your database schema will evolve as your project grows. Django's migration system provides a powerful way to propagate changes you make to your models into your database schema. This tutorial will guide you through understanding and working with Django's migration system.

Understanding Database Migrations

A database migration is a way to update your database schema from one state to another. Instead of manually writing SQL to modify your database schema, Django creates migration files that:

  1. Record changes to your models
  2. Can be applied to update the database schema
  3. Can be reversed to undo changes
  4. Keep your database schema in sync with your Django models

Why Migrations Matter

When deploying Django applications, proper migration management is crucial because:

  • They ensure consistent database structure across all environments
  • They allow multiple developers to work on the same project without database conflicts
  • They provide a versioned history of your database schema
  • They make deployment safer by allowing controlled database changes

Basic Migration Commands

Django provides several commands for working with migrations:

Creating Migrations

When you make changes to your models (adding, modifying, or removing fields), you need to create a migration:

bash
python manage.py makemigrations

For a specific app:

bash
python manage.py makemigrations myapp

Output:

Migrations for 'myapp':
myapp/migrations/0001_initial.py
- Create model BlogPost

Applying Migrations

To apply migrations and update your database schema:

bash
python manage.py migrate

For a specific app:

bash
python manage.py migrate myapp

Output:

Operations to perform:
Apply all migrations: myapp
Running migrations:
Applying myapp.0001_initial... OK

Checking Migration Status

To see which migrations have been applied and which are pending:

bash
python manage.py showmigrations

Output:

admin
[X] 0001_initial
[X] 0002_logentry_remove_auto_add
myapp
[X] 0001_initial
[ ] 0002_add_author_field

Migration SQL

To see the SQL statements that will be executed for a migration:

bash
python manage.py sqlmigrate myapp 0001

Output:

sql
BEGIN;
--
-- Create model BlogPost
--
CREATE TABLE "myapp_blogpost" (
"id" integer NOT NULL PRIMARY KEY AUTOINCREMENT,
"title" varchar(200) NOT NULL,
"content" text NOT NULL,
"created_at" datetime NOT NULL
);
COMMIT;

Creating a Migration Workflow

Let's work through a practical example of the migration workflow.

1. Create an Initial Model

Let's start with a simple blog post model in models.py:

python
from django.db import models

class BlogPost(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)

def __str__(self):
return self.title

2. Create the Initial Migration

bash
python manage.py makemigrations myapp

This creates your first migration file, typically named 0001_initial.py.

3. Apply the Migration

bash
python manage.py migrate myapp

Now your database has a table for the BlogPost model.

4. Update the Model

Let's add an author field:

python
from django.db import models

class BlogPost(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
author = models.CharField(max_length=100, default='Anonymous')

def __str__(self):
return self.title

5. Create a Migration for the Changes

bash
python manage.py makemigrations myapp

Output:

Migrations for 'myapp':
myapp/migrations/0002_blogpost_author.py
- Add field author to blogpost

6. Apply the New Migration

bash
python manage.py migrate myapp

Now your database schema includes the author field.

Advanced Migration Techniques

Data Migrations

Sometimes you need to not just change the schema but also modify existing data. Django provides data migrations for this purpose.

Create an empty migration:

bash
python manage.py makemigrations --empty myapp

Edit the migration file:

python
from django.db import migrations

def set_default_authors(apps, schema_editor):
BlogPost = apps.get_model('myapp', 'BlogPost')
# Update all posts with blank authors
BlogPost.objects.filter(author='').update(author='Admin User')

class Migration(migrations.Migration):

dependencies = [
('myapp', '0002_blogpost_author'),
]

operations = [
migrations.RunPython(set_default_authors),
]

Handling Migration Dependencies

Sometimes migrations depend on each other. Django automatically manages these dependencies, but you might need to specify them manually in complex scenarios:

python
class Migration(migrations.Migration):

dependencies = [
('myapp', '0002_blogpost_author'),
('users', '0001_initial'),
]

# Migration operations...

Reversing Migrations

To undo a specific migration:

bash
python manage.py migrate myapp 0001

This will revert back to migration 0001, undoing any later migrations.

Squashing Migrations

Over time, you might accumulate many migration files. You can squash them into fewer files:

bash
python manage.py squashmigrations myapp 0001 0004

This combines migrations 0001 through 0004 into a single migration.

Migration Best Practices for Deployment

When deploying Django applications:

1. Always Run Migrations During Deployment

Include migration application in your deployment script:

bash
python manage.py migrate --noinput

The --noinput flag prevents Django from asking for user input during deployment.

2. Never Edit Applied Migrations

Once a migration has been applied and pushed to version control, treat it as immutable. If you need to correct something, create a new migration.

3. Test Migrations Before Deploying

Always test migrations on a copy of production data before applying them to your production database.

4. Back Up Your Database Before Migrating

Always back up your database before running migrations in production:

bash
pg_dump mydatabase > backup.sql  # For PostgreSQL

5. Consider Zero-Downtime Migrations

For large tables or critical applications, consider:

Troubleshooting Common Migration Issues

Conflicting Migrations

If multiple developers create migrations simultaneously, you might get conflicts:

bash
CommandError: Conflicting migrations detected; multiple leaf nodes in the migration graph

Solution: Discuss with your team which migration should be kept, then:

bash
python manage.py makemigrations --merge

Unapplied Migration Warnings

Your models have changes that are not yet reflected in a migration...

Solution: Run python manage.py makemigrations to create missing migrations.

Migration Dependency Errors

Migration myapp.0002_dependency depends on unknown app.migration: users.0001_initial

Solution: Ensure all required apps are installed and migrations are in the correct order.

Practical Example: Complete Deployment Migration Strategy

Here's an example of how migrations fit into a deployment strategy:

  1. Local Development

    bash
    # After model changes
    python manage.py makemigrations
    python manage.py migrate
    # Run tests
    python manage.py test
  2. Continuous Integration

    bash
    # In CI pipeline
    python manage.py migrate --check # Verify no unapplied migrations
    python manage.py test
  3. Staging Deployment

    bash
    # On staging server
    git pull
    python manage.py migrate
    # restart application server
  4. Production Deployment

    bash
    # On production server
    pg_dump -U username database > backup_$(date +%F).sql
    git pull
    python manage.py migrate
    # restart application server

Summary

Django's migration system is a powerful tool for managing database schema changes throughout your application's lifecycle. By following best practices and understanding the migration commands, you can ensure smooth database evolution across development and deployment environments.

Key points to remember:

  • Migrations track changes to your models and apply them to the database
  • Always create migrations after model changes with makemigrations
  • Apply migrations with the migrate command
  • Test migrations thoroughly before applying them to production
  • Include migrations in your deployment process

Additional Resources

Exercises

  1. Create a Django app with a model, make several model changes, and practice creating and applying migrations.
  2. Write a data migration to populate a new field on existing records.
  3. Simulate a migration conflict between two developers and practice resolving it.
  4. Create a deployment script that includes proper database backup and migration steps.
  5. Practice squashing migrations on a test project with multiple migration files.


If you spot any mistakes on this website, please let me know at [email protected]. I’d greatly appreciate your feedback! :)