Skip to content

第5章:数据库操作

5.2 Django 迁移系统

迁移概念

Django的迁移系统是一个版本控制系统,用于管理数据库模式的变更。它允许开发者:

  • 跟踪数据库模式的变化
  • 在不同环境之间同步数据库结构
  • 回滚不需要的数据库变更

迁移命令

创建迁移文件

bash
# 为所有已更改的模型创建迁移文件
python manage.py makemigrations

# 为特定应用创建迁移文件
python manage.py makemigrations app_name

# 为特定模型创建迁移文件
python manage.py makemigrations app_name --name migration_name

# 空迁移文件(手动编写迁移操作)
python manage.py makemigrations --empty app_name

应用迁移

bash
# 应用所有未应用的迁移
python manage.py migrate

# 为特定应用应用迁移
python manage.py migrate app_name

# 应用到特定迁移版本
python manage.py migrate app_name 0002_some_migration

# 显示迁移状态
python manage.py showmigrations

回滚迁移

bash
# 回滚到上一个迁移版本
python manage.py migrate app_name previous_migration_number

# 回滚所有迁移(重置数据库)
python manage.py migrate app_name zero

迁移文件解析

迁移文件位于每个应用的 migrations/ 目录中,文件名格式为 0001_initial.py

python
# 示例迁移文件
from django.db import migrations, models

class Migration(migrations.Migration):
    # 依赖关系
    dependencies = [
        ('app_name', '0001_initial'),
    ]

    # 数据库操作
    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),
        ),
    ]

迁移操作类型

Django提供了多种迁移操作:

1. 模型操作

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

2. 字段操作

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. 索引和约束

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'),
)

数据迁移

除了模式迁移,还可以创建数据迁移:

bash
# 创建空的数据迁移文件
python manage.py makemigrations --empty app_name

然后在生成的迁移文件中添加数据操作:

python
from django.db import migrations

def add_initial_data(apps, schema_editor):
    # 获取模型类
    Article = apps.get_model('blog', 'Article')
    
    # 创建初始数据
    Article.objects.create(
        title='欢迎使用Django',
        content='这是第一篇文章内容...',
        published=True
    )

def reverse_data(apps, schema_editor):
    # 回滚操作
    Article = apps.get_model('blog', 'Article')
    Article.objects.filter(title='欢迎使用Django').delete()

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

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

自定义迁移操作

可以创建自定义的迁移操作:

python
from django.db import migrations, models

class CustomOperation(migrations.Operation):
    reversible = True

    def state_forwards(self, app_label, state):
        # 修改状态
        pass

    def database_forwards(self, app_label, schema_editor, from_state, to_state):
        # 数据库前进操作
        pass

    def database_backwards(self, app_label, schema_editor, from_state, to_state):
        # 数据库回滚操作
        pass

迁移依赖关系

迁移文件可以指定依赖关系:

python
class Migration(migrations.Migration):
    # 依赖其他应用的迁移
    dependencies = [
        ('auth', '0012_alter_user_first_name_max_length'),
        ('contenttypes', '0002_remove_content_type_name'),
    ]

    # 依赖同一应用的其他迁移
    dependencies = [
        ('blog', '0001_initial'),
    ]

迁移最佳实践

1. 小步提交

bash
# 每次只做一个小的变更
python manage.py makemigrations
python manage.py migrate

2. 测试迁移

bash
# 在测试环境中测试迁移
python manage.py test --migrate

3. 版本控制

bash
# 将迁移文件纳入版本控制
git add app/migrations/

4. 处理冲突

bash
# 当迁移冲突时,可以手动合并或重新生成
python manage.py makemigrations --merge

常见问题解决

迁移冲突

当多个开发者同时创建迁移时可能发生冲突:

bash
# 查看冲突
python manage.py showmigrations --conflict

# 合并冲突
python manage.py makemigrations --merge

重置迁移

在开发早期可以重置迁移:

bash
# 删除所有迁移文件
find . -path "*/migrations/*.py" -not -name "__init__.py" -delete
find . -path "*/migrations/*.pyc" -delete

# 重新创建初始迁移
python manage.py makemigrations
python manage.py migrate

手动修改迁移

有时需要手动编辑迁移文件:

python
# 修改依赖关系
dependencies = [
    ('app_name', '0001_initial'),
    # 添加额外的依赖
    ('other_app', '0002_some_migration'),
]

# 修改操作顺序
operations = [
    # 调整操作顺序
    migrations.AddField(...),
    migrations.AlterField(...),
]

生产环境迁移

在生产环境中执行迁移需要谨慎:

bash
# 先备份数据库
python manage.py dumpdata > backup.json

# 测试迁移
python manage.py migrate --dry-run

# 应用迁移
python manage.py migrate

# 如果有问题,回滚
python manage.py migrate app_name previous_version

迁移工具和扩展

Django Migration Linter

检查迁移文件的兼容性问题:

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

Django-Tenants

多租户数据库迁移:

bash
pip install django-tenants
python manage.py migrate_schemas

小结

Django迁移系统是数据库版本控制的强大工具:

  1. ✅ 通过 makemigrationsmigrate 命令管理数据库变更
  2. ✅ 支持模式迁移和数据迁移
  3. ✅ 提供回滚和冲突解决机制
  4. ✅ 支持多数据库和自定义操作
  5. ✅ 生产环境安全迁移的最佳实践

掌握迁移系统能够确保数据库结构变更的安全性和一致性。

下一篇

我们将学习QuerySet和数据库API,了解如何高效地查询和操作数据。

5.3 QuerySet和数据库API →

目录

返回课程目录

Released under the Apache 2.0 License.