Skip to content

Chapter 5: Database Operations

5.2 Django Migration System

Migration Concept

Django's migration system is a version control system for managing database schema changes. It allows developers to:

  • Track changes to database schemas
  • Synchronize database structures across different environments
  • Roll back unwanted database changes

Migration Commands

Creating Migration Files

bash
# Create migration files for all changed models
python manage.py makemigrations

# Create migration files for a specific app
python manage.py makemigrations app_name

# Create migration files for a specific model
python manage.py makemigrations app_name --name migration_name

# Empty migration file (manually write migration operations)
python manage.py makemigrations --empty app_name

Applying Migrations

bash
# Apply all unapplied migrations
python manage.py migrate

# Apply migrations for a specific app
python manage.py migrate app_name

# Apply to a specific migration version
python manage.py migrate app_name 0002_some_migration

# Show migration status
python manage.py showmigrations

Rolling Back Migrations

bash
# Roll back to the previous migration version
python manage.py migrate app_name previous_migration_number

# Roll back all migrations (reset database)
python manage.py migrate app_name zero

Migration File Analysis

Migration files are located in the migrations/ directory of each app, with file names in the format 0001_initial.py:

python
# Example migration file
from django.db import migrations, models

class Migration(migrations.Migration):
    # Dependencies
    dependencies = [
        ('app_name', '0001_initial'),
    ]

    # Database operations
    operations = [
        migrations.CreateModel(
            name='Article',
            fields=[
                ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
                ('title', models.CharField(max_length=200)),
                ('content', models.TextField()),
                ('created_at', models.DateTimeField(auto_now_add=True)),
            ],
        ),
        migrations.AddField(
            model_name='article',
            name='published',
            field=models.BooleanField(default=False),
        ),
    ]

Migration Operation Types

Django provides various migration operations:

1. Model Operations

python
migrations.CreateModel(
    name='ModelName',
    fields=[...],
    options={...},
    bases=(...),
)
migrations.DeleteModel(name='ModelName')

2. Field Operations

python
migrations.AddField(
    model_name='modelname',
    name='fieldname',
    field=models.CharField(max_length=100),
)
migrations.RemoveField(
    model_name='modelname',
    name='fieldname',
)
migrations.AlterField(
    model_name='modelname',
    name='fieldname',
    field=models.TextField(),
)

3. Indexes and Constraints

python
migrations.AddIndex(
    model_name='modelname',
    index=models.Index(fields=['field1', 'field2'], name='index_name'),
)
migrations.AddConstraint(
    model_name='modelname',
    constraint=models.UniqueConstraint(fields=['field1', 'field2'], name='constraint_name'),
)

Data Migrations

In addition to schema migrations, data migrations can also be created:

bash
# Create an empty data migration file
python manage.py makemigrations --empty app_name

Then add data operations in the generated migration file:

python
from django.db import migrations

def add_initial_data(apps, schema_editor):
    # Get model class
    Article = apps.get_model('blog', 'Article')
    
    # Create initial data
    Article.objects.create(
        title='Welcome to Django',
        content='This is the first article content...',
        published=True
    )

def reverse_data(apps, schema_editor):
    # Rollback operation
    Article = apps.get_model('blog', 'Article')
    Article.objects.filter(title='Welcome to Django').delete()

class Migration(migrations.Migration):
    dependencies = [
        ('blog', '0001_initial'),
    ]

    operations = [
        migrations.RunPython(add_initial_data, reverse_data),
    ]

Custom Migration Operations

Custom migration operations can be created:

python
from django.db import migrations, models

class CustomOperation(migrations.Operation):
    reversible = True

    def state_forwards(self, app_label, state):
        # Modify state
        pass

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        # Database forward operation
        pass

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        # Database rollback operation
        pass

Migration Dependencies

Migration files can specify dependencies:

python
class Migration(migrations.Migration):
    # Depend on migrations from other apps
    dependencies = [
        ('auth', '0012_alter_user_first_name_max_length'),
        ('contenttypes', '0002_remove_content_type_name'),
    ]

    # Depend on other migrations from the same app
    dependencies = [
        ('blog', '0001_initial'),
    ]

Migration Best Practices

1. Small Commits

bash
# Make only small changes at a time
python manage.py makemigrations
python manage.py migrate

2. Test Migrations

bash
# Test migrations in test environment
python manage.py test --migrate

3. Version Control

bash
# Include migration files in version control
git add app/migrations/

4. Handling Conflicts

bash
# When migration conflicts occur, merge manually or regenerate
python manage.py makemigrations --merge

Common Problem Solutions

Migration Conflicts

Conflicts may occur when multiple developers create migrations simultaneously:

bash
# View conflicts
python manage.py showmigrations --conflict

# Merge conflicts
python manage.py makemigrations --merge

Resetting Migrations

Migrations can be reset during early development:

bash
# Delete all migration files
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc" -delete

# Recreate initial migrations
python manage.py makemigrations
python manage.py migrate

Manual Migration Modification

Sometimes migration files need to be manually edited:

python
# Modify dependencies
dependencies = [
    ('app_name', '0001_initial'),
    # Add additional dependencies
    ('other_app', '0002_some_migration'),
]

# Modify operation order
operations = [
    # Adjust operation order
    migrations.AddField(...),
    migrations.AlterField(...),
]

Production Environment Migrations

Executing migrations in production environments requires caution:

bash
# Backup database first
python manage.py dumpdata > backup.json

# Test migration
python manage.py migrate --dry-run

# Apply migration
python manage.py migrate

# If there's a problem, roll back
python manage.py migrate app_name previous_version

Migration Tools and Extensions

Django Migration Linter

Check migration file compatibility issues:

bash
pip install django-migration-linter
python manage.py lintmigrations

Django-Tenants

Multi-tenant database migrations:

bash
pip install django-tenants
python manage.py migrate_schemas

Summary

Django migration system is a powerful tool for database version control:

  1. ✅ Manage database changes through makemigrations and migrate commands
  2. ✅ Support schema migrations and data migrations
  3. ✅ Provide rollback and conflict resolution mechanisms
  4. ✅ Support multi-database and custom operations
  5. ✅ Best practices for safe migrations in production environments

Mastering the migration system ensures the safety and consistency of database structure changes.

Next

We will learn about QuerySet and database API, understanding how to efficiently query and manipulate data.

5.3 QuerySet and Database API →

Contents

Back to Course Outline

Released under the [BY-NC-ND License](https://creativecommons.org/licenses/by-nc-nd/4.0/deed.en).