Django通过ORM来操作数据库,而其中数据库表结构的创建和变更因为尤其重要所以Django需要对其每一次的操作都进行记录和留档,以实现每次只执行增量变更,同时方便回溯和回退。Django中专门负责这一记录功能的模块叫迁移(migrate)。这一篇我们一起来看看迁移的原理和操作步骤,以及出错时的回退。
我是T型人小付,一位坚持终身学习的互联网从业者。喜欢我的博客欢迎在csdn上关注我,如果有问题欢迎在底下的评论区交流,谢谢。
迁移的原理
模型类
所谓ORM就是将面向对象的python操作转变为数据库可识别的SQL语句,而数据库中每张表对应着Django中的一个模型类,也就是在models.py
中定义的一个class
。所以创建一张张SQL表也就变成了定义一个个模型类,而修改表结构也就变成了修改类属性,这是理解MTV中M,也就是models的核心思想。
例如下面是models.py
中定义的三个类,分别是People
,American
,Chinese
。这里的People
是另两个的父类,不过这里可以忽略
class People(models.Model):
p_name = models.CharField(max_length=16)
p_sex = models.BooleanField(default=True)
class American(People):
a_state = models.CharField(max_length=16)
class Chinese(People):
c_province = models.CharField(max_length=16)
完成了ORM映射,就变成了数据库里面的三张表。这里表名带的Four
前缀是应用的名字,不用管
增量操作
一个models.py
中写着所有的模型类,每一次对单个类做的微小的修改,不可能让所有表都跟着再做一次SQL操作,所以务必得是增量操作。
Django项目里的每一个应用都自带一个migrations
目录,每次执行跟表结构变更相关的操作,都会在这里生成增量的操作文件,这些文件叫做迁移文件。
例如上面定义了三个类,在执行生成迁移文件操作之后,新增了下面这个文件
文件内容如下
class Migration(migrations.Migration):
dependencies = [
('Four', '0003_auto_20200401_2321'),
]
operations = [
migrations.CreateModel(
name='People',
fields=[
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
('p_name', models.CharField(max_length=16)),
('p_sex', models.BooleanField(default=True)),
],
),
migrations.CreateModel(
name='American',
fields=[
('people_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='Four.People')),
('a_state', models.CharField(max_length=16)),
],
bases=('Four.people',),
),
migrations.CreateModel(
name='Chinese',
fields=[
('people_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='Four.People')),
('c_province', models.CharField(max_length=16)),
],
bases=('Four.people',),
),
]
注意其中的这一部分
dependencies = [
('Four', '0003_auto_20200401_2321'),
]
这就是本次执行的上一次执行,也就是说等0003_auto_20200401_2321
这个迁移文件中的操作完成以后再执行本文件中的操作。
执行时序
从上面可以看出,migrations
目录中的众多迁移文件对应着一批批的操作,这些文件被按照时间顺序先后执行就完成了最终的结果。
那么Django怎么知道某一个文件有没有被执行过呢?
这个也很简单,对每一次完成的操作记录一下时间就可以了。这些操作都被记录在项目自带的django_migrations
表中。打开django_migrations
表看一下
可以看到对于应用Four
一共执行过四次操作,最后一次操作就是我们刚才创建三个表的0004_american_chinese_people
文件。
迁移的步骤
有了上面的原理做为铺垫,梳理出迁移的操作步骤就不难了。
- 首先在
models.py
中创建或者修改模型类 - 跑
python manager.py makemigrations
创建本次修改的迁移文件,此时会去数据库中查找上一次执行的文件并记录在本文件中 - 然后执行
python manager.py migrate
执行迁移,将变更同步到数据库中
迁移的回退
假如某次操作涉及的操作太细碎,迁移后的效果不理想,最好的办法就是回退到上一次迁移的时候。
Django为我们创建了快捷的回退操作,直接对前一步的迁移文件重新手动迁移一次即可完成回退操作。
以上面创建三个表为例,直接再跑python manage.py migrate Four 0003_auto_20200401_2321
即可。记得带上Four
这个应用名
[fuhx@testmachine DjangoModel]$ python manage.py migrate Four 0003_auto_20200401_2321
Operations to perform:
Target specific migration: 0003_auto_20200401_2321, from Four
Running migrations:
Rendering model states... DONE
Unapplying Four.0004_american_chinese_people... OK
之后会发现数据库中的三张表被自动删除了,同时django_migrations
表中最后一条记录也没了
之后别忘了手动删除migrations目录中的0004号迁移文件,从而完成回退动作。