本文目录导读:
是的,Django 的迁移系统确实是一个非常强大且设计精良的工具,用于管理数据库模式(schema)的变更,通过一个具体的案例,可以很好地理解它的核心概念和工作流程。
下面我为你构建一个典型的“博客应用”开发案例,并逐步演示 Django 如何通过迁移系统来管理数据库变化。
案例:构建一个简单的博客应用
目标: 开发一个博客应用,需要存储作者和文章信息。
第一阶段:初始模型与迁移
-
定义模型 (
models.py)# blog/models.py from django.db import models class Author(models.Model): name = models.CharField(max_length=100) email = models.EmailField() def __str__(self): return self.name class Article(models.Model): title = models.CharField(max_length=200) content = models.TextField() pub_date = models.DateTimeField('date published') author = models.ForeignKey(Author, on_delete=models.CASCADE) def __str__(self): return self.title -
生成迁移文件
运行命令:
python manage.py makemigrations blog
发生了什么? Django 会扫描
blog/models.py文件,与blog/migrations/目录下已有的迁移文件进行比较,由于这是第一次,它会检测到Author和Article这两个新模型,并自动创建一个迁移文件(0001_initial.py)。迁移文件内部(简化版):
# blog/migrations/0001_initial.py from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [] operations = [ migrations.CreateModel( name='Author', fields=[ ('id', models.AutoField(...)), ('name', models.CharField(max_length=100)), ('email', models.EmailField()), ], ), migrations.CreateModel( name='Article', fields=[ ('id', models.AutoField(...)), ('title', models.CharField(max_length=200)), ('content', models.TextField()), ('pub_date', models.DateTimeField(...)), ('author', models.ForeignKey(to='blog.Author', ...)), ], ), ] -
应用迁移到数据库
运行命令:
python manage.py migrate blog
发生了什么? Django 会执行
0001_initial.py中的操作,在数据库中创建blog_author和blog_article两张表,包括所有字段、约束、索引和外键关系,Django 会记录本次迁移的执行状态(在django_migrations表中插入一条记录)。
第二阶段:需求变更,修改模型
新需求: 文章增加一个 status 字段(草稿/已发布),Article 模型需要增加一个 category(分类)字段,Author 要增加一个 bio(简介)字段。
-
修改模型 (
models.py)# blog/models.py from django.db import models class Author(models.Model): name = models.CharField(max_length=100) email = models.EmailField() bio = models.TextField(blank=True) # 新增字段 class Article(models.Model): title = models.CharField(max_length=200) content = models.TextField() pub_date = models.DateTimeField('date published') author = models.ForeignKey(Author, on_delete=models.CASCADE) status = models.CharField( # 新增字段 max_length=10, choices=[('draft', 'Draft'), ('published', 'Published')], default='draft' ) category = models.CharField(max_length=50, null=True) # 新增字段,允许为空 -
再次生成迁移文件
运行命令:
python manage.py makemigrations blog
发生了什么? Django 再次比较当前模型与
0001_initial.py的差异,它会发现:Author模型多了一个bio字段。Article模型多了status和category字段。- 自动生成一个新的迁移文件(
0002_article_status_author_bio_category.py)。
迁移文件内部(简化版):
# blog/migrations/0002_article_status_author_bio_category.py from django.db import migrations, models class Migration(migrations.Migration): dependencies = [ ('blog', '0001_initial'), # 依赖之前的迁移 ] operations = [ migrations.AddField( model_name='author', name='bio', field=models.TextField(blank=True), ), migrations.AddField( model_name='article', name='status', field=models.CharField( choices=[('draft', 'Draft'), ('published', 'Published')], default='draft', max_length=10 ), ), migrations.AddField( model_name='article', name='category', field=models.CharField(max_length=50, null=True), ), ] -
应用新的迁移
运行命令:
python manage.py migrate blog
发生了什么? Django 执行
0002_...迁移文件,在数据库的blog_author表中添加bio列(可空),在blog_article表中添加status和category列,如果表中有已有数据,对于status字段,Django 会知道设置默认值'draft';对于category字段,由于允许为空,已存在的行该字段会为NULL。
第三阶段:撤销迁移
新问题: 发现 category 字段设计不合理,需要回滚。
-
回滚到上一个版本
python manage.py migrate blog 0001
发生了什么? Django 会找到从
0002回退到0001所需的所有操作,并自动执行反向操作(如RemoveField),数据库中的bio、status、category列都会被删除(注意:这会丢失数据!)。
通过这个案例,我们可以清晰地看到 Django 迁移系统的关键特性:
- 版本控制:每个迁移文件(
0001_initial.py、0002_...)都是一个数据库模式的“版本快照”。 - 依赖链:迁移文件通过
dependencies属性形成链条(0002依赖于0001),这保证了正确的执行顺序,并允许跨应用迁移。 - 声明式 vs 命令式:你声明模型(
models.py),Django 自动分析差异并生成命令式的迁移文件(AddField、CreateModel等操作)。 - 可逆性:迁移操作通常都有对应的反向操作(
CreateModel的反向是DeleteModel,AddField的反向是RemoveField),这使得回滚非常可靠。 - 历史追踪:
django_migrations表记录了每个迁移是否已被应用,防止重复执行或冲突。
为什么这对你理解Django很重要?
- 开发协作:团队成员可以独立生成迁移,合并时进行冲突处理。
- 数据安全:合理的迁移流程可以避免手动修改数据库导致的灾难性错误。
- 部署自动化:
migrate命令可以安全地在生产环境执行,完成数据库升级。 - 适应变化:业务需求经常变化,强大的迁移系统让数据库模式变更变得低成本、可预测。
这个案例应该能帮助你直观地抓住迁移系统的精髓:它把数据库的变更历史,变成了与代码一样可追踪、可撤销、可协作的版本化操作序列。
标签: 迁移系统