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).