Django 迁移系统全指南:从模型到数据库的魔法之路
前言
你是否曾经遇到过这样的困扰:写好了一个 Python 的 models.py 文件,却发现不知道怎么在数据库中创建对应的表?或者修改了模型定义后,手动去数据库改表结构改得焦头烂额?
别担心,Django 的迁移系统就是为了解决这个问题而生的!今天我们就来深入了解一下这个强大的工具。
一、什么是 Django 迁移系统?
Django 迁移系统是一个自动化的数据库版本控制系统,它可以:
- 📊 自动检测模型变化
- 📝 生成迁移文件记录变化历史
- 🚀 自动执行 SQL 来更新数据库
简单来说,你只需要写 Python 代码,剩下的事情 Django 都帮你搞定!
二、核心概念:两个命令
2.1 python manage.py makemigrations - 施工图纸
这个命令负责检测模型变化 并生成迁移文件。
python
# apps/students/models.py
class Student(models.Model):
name = models.CharField(max_length=100)
age = models.IntegerField() # 假设这是我们新增的字段
运行命令后:
bash
$ python manage.py makemigrations
Migrations for 'students':
apps/students/migrations/0002_add_age_field.py
- Add field age to student
Django 会在 apps/students/migrations/ 目录下生成一个新的 Python 文件:
python
# 0002_add_age_field.py
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
('students', '0001_initial'),
]
operations = [
migrations.AddField(
model_name='student',
name='age',
field=models.IntegerField(),
),
]
⚠️ 注意 :这个命令不会修改数据库,它只是准备了"施工图纸"。
2.2 python manage.py migrate - 真正施工
这个命令负责执行迁移文件 并修改数据库。
bash
$ python manage.py migrate
Running migrations:
Applying students.0002_add_age_field... OK
Django 会读取刚才生成的迁移文件,执行相应的 SQL:
sql
ALTER TABLE students_student ADD COLUMN age INT;
并且会在 django_migrations 表中记录这个迁移已经被应用,防止重复执行。
三、两者的关系
可以用一个简单的类比来理解:
┌─────────────────────────────────────────────────────────┐
│ makemigrations = 编写施工图纸 │
│ (检测模型变化,生成迁移文件) │
└──────────────────────┬──────────────────────────────────┘
↓
┌─────────────────────────────────────────────────────────┐
│ migrate = 按照图纸施工 │
│ (执行 SQL,修改数据库) │
└─────────────────────────────────────────────────────────┘
四、完整的工作流程
场景:为学生表添加性别字段
第一步:修改模型
python
# apps/students/models.py
class Student(models.Model):
name = models.CharField(max_length=100, verbose_name='姓名')
age = models.IntegerField(verbose_name='年龄')
gender = models.CharField(
max_length=10,
choices=[('male', '男'), ('female', '女')],
default='male',
verbose_name='性别'
) # 新增字段
第二步:生成迁移文件
bash
$ python manage.py makemigrations
Migrations for 'students':
apps/students/migrations/0003_add_gender_field.py
- Add field gender to student
第三步:应用迁移
bash
$ python manage.py migrate
Running migrations:
Applying students.0003_add_gender_field... OK
第四步:查看结果
sql
mysql> DESCRIBE students_student;
+-------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------+--------------+------+-----+---------+----------------+
| id | bigint | NO | PRI | NULL | auto_increment |
| name | varchar(100) | NO | | NULL | |
| age | int | NO | | NULL | |
| gender| varchar(10) | NO | | male | |
+-------+--------------+------+-----+---------+----------------+
搞定!数据库表已经自动更新了!
五、Django 会自动做什么?
✅ Django ORM 自动处理的:
| 操作 | 示例 | 生成的 SQL |
|---|---|---|
| 创建表 | 创建 Student 模型 |
CREATE TABLE |
| 添加字段 | 新增 gender 字段 |
ALTER TABLE ADD COLUMN |
| 修改字段 | 修改 name 字段长度 |
ALTER TABLE MODIFY COLUMN |
| 删除字段 | 删除 age 字段 |
ALTER TABLE DROP COLUMN |
| 创建索引 | index=True |
CREATE INDEX |
| 外键关系 | ForeignKey |
FOREIGN KEY |
| 多对多 | ManyToManyField |
自动创建中间表 |
❌ Django 不会做的:
- 创建数据库本身 (需要手动执行
CREATE DATABASE) - 删除数据库
- 数据库的备份和恢复
六、典型场景示例
场景 1:项目初始化
bash
# 1. 创建数据库(手动做一次)
mysql -u root -p
CREATE DATABASE myproject CHARACTER SET utf8mb4;
exit;
# 2. 配置 settings.py
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.mysql',
'NAME': 'myproject',
'USER': 'root',
'PASSWORD': 'password',
'HOST': 'localhost',
'PORT': '3306',
}
}
# 3. 运行迁移(创建所有表)
python manage.py migrate
场景 2:开发过程中修改模型
bash
# 修改 models.py 后
python manage.py makemigrations # 检测变化
python manage.py migrate # 应用到数据库
场景 3:团队协作
bash
# 同事 A 修改了模型并提交代码
git pull
# 同事 B 拉取代码后
python manage.py makemigrations # 检查是否有新迁移
python manage.py migrate # 应用迁移
七、常见问题与解决方案
Q1: 如果数据库表已经存在怎么办?
情况 1:表是通过 SQL 手动创建的
bash
# 先创建空迁移(不执行 SQL)
python manage.py makemigrations --empty
# 然后标记为已应用(告诉 Django 表已存在)
python manage.py migrate --fake
情况 2:数据库为空,直接运行迁移
bash
python manage.py migrate
Q2: 如何查看迁移历史?
bash
# 查看所有迁移
python manage.py showmigrations
# 查看某个应用的迁移
python manage.py showmigrations students
# 查看迁移将执行的 SQL(不实际执行)
python manage.py sqlmigrate students 0002
Q3: 如何撤销迁移?
bash
# 撤销最后一次迁移(未应用)
python manage.py migrate students 0001
# 删除迁移文件(未应用)
rm apps/students/migrations/0002_add_age_field.py
Q4: 迁移冲突怎么办?
当多人同时修改同一个模型时可能出现冲突:
bash
# 1. 创建新的迁移解决冲突
python manage.py makemigrations --merge
# 2. 应用迁移
python manage.py migrate
八、最佳实践
✅ 推荐做法:
-
每次修改模型后立即运行迁移
bashpython manage.py makemigrations && python manage.py migrate -
将迁移文件纳入版本控制
bashgit add apps/*/migrations/*.py git commit -m "Add age field to Student" -
不要手动修改迁移文件
- 迁移文件由 Django 自动生成和依赖
- 手动修改可能导致问题
-
生产环境部署前先在测试环境验证
bash# 测试环境 python manage.py migrate --plan # 查看将要执行的操作
❌ 避免的做法:
- 不要直接修改数据库表结构
- 不要删除已应用的迁移文件
- 不要在生产环境运行
makemigrations
九、总结对比表
| 特性 | makemigrations | migrate |
|---|---|---|
| 作用 | 检测模型变化,生成迁移文件 | 执行迁移,修改数据库 |
| 修改数据库 | ❌ 不修改 | ✅ 执行 SQL |
| 产生文件 | ✅ 生成 .py 文件 |
❌ 不产生文件 |
| 何时使用 | 修改 models.py 后 |
生成迁移文件后 |
| 执行次数 | 每次修改模型 | 每次有新迁移 |
| 可以撤销 | 可以删除未应用的迁移 | 可以回退到之前的版本 |
十、进阶技巧
1. 查看迁移计划(不执行)
bash
python manage.py migrate --plan
2. 只运行特定应用的迁移
bash
python manage.py migrate students
3. 回退到指定迁移
bash
python manage.py migrate students 0001
4. 生成空的迁移(用于自定义操作)
bash
python manage.py makemigrations --empty students
结语
Django 的迁移系统是一个强大而优雅的数据库管理工具,它让开发者能够专注于业务逻辑,而不是繁琐的 SQL 操作。
记住这两个命令:
bash
python manage.py makemigrations # 检测变化,生成迁移文件
python manage.py migrate # 应用迁移,修改数据库
就这么简单!🎉
相关资源:
希望这篇博客能帮助你理解 Django 的迁移系统!如果还有疑问,欢迎留言讨论!💬