简介
模型对象django内置了ORM
,它在操作数据库时一般情况下无需直接写sql语句,而是用常规面向对象的方式调用模型对象
的方法和属性,django框架底层会自动转为sql操纵数据库。 开发者要管理好这个ORM
模型和DB的关系,背后需要理解几个django定义的几个有关迁移的命令。
- makemigrations
- migrate
- showmigrations
- sqlmigrate
迁移原理
关于迁移原理有4个点先介绍下
- 模型model类代码
- App下的migrations包(文件夹)
- DB里的django_migrations表
- DB里的模型对应表
迁移命令就是操作以上的4个中的某些点来进行的,目的是实现将模型model类代码
的字段/属性/方法的定义,转化为DB里的模型对应表
即数据库表结构的定义,需求总是不断变化的,那么中间的2和3是为了记录model的改变历史,和以增量的方式保存迁移动作。
migrations包:
里面是0001_xxx.py~000N_xxx.py的文件,是变迁记录文件,注意有一个名字包含initial
的,其他是包含日期的;initial
的文件是首次创建时使用的,里面主要是创建表CreateModel
的动作;其他的是随着model类改变(比如增删字段),这里阶段性地记录表结构的变化,多为AddField
动作。这些py文件在migrate的时候都会翻译成sql。
django_migrations表:
数据库表,每行记录对应上面migrations包的一个py文件,表示已执行过了,并能清楚看到执行时间。
命令说明
1. makemigrations
为app创建迁移文件,生成的文件放在各app的migrations包下;执行时会先检查已存在migrations包里的历史文件,在历史文件的基础上生成变更的迁移文件。
如果没变更,则不需生成,提示No changes detected
。
该命令无需与DB交互,只检查本地记录。
2. migrate
执行具体的迁移动作,执行操作到DB上;先拿migrations包下的文件名和DB里django_migrations表里的记录比较,如果表里不存在说明未执行,则将待迁移的py文件翻译成sql语句(这些语句一般为创建表和修改表结构),并在DB上执行,如果执行成功则在django_migrations表内插入该记录,如果失败则raise异常退出,整个操作DB过程使用事务进行。
该命令有两个参数比较实用,需要掌握
- fake
- fake-intial
官方解释
--fake Mark migrations as run without actually running them
--fake-initial Detect if tables already exist and fake-apply initial
migrations if so. Make sure that the current database
schema matches your initial migration before using
this flag. Django will only check for an existing
table name.
第一个--fake
是在迁移过程不真正(跳过)执行操作模型表的sql,django_migrations表插入记录还是照做的。
第二个--fake-initial
是跳过初始化数据库那一步(即0001_initial.py);比
--fake
还缩小了范围,仅跳过初始化部分,其他修改表结果啊增删字段的增量迁移还是会真正执行的,这里要尤其注意。
另外这所谓的跳过初始化还有如下特征,a.先检查模型对应的表是否存在,如果存在则跳过,如果不存在则会创建表;
b.当0001_initial.py里有多个model时,要么全部表都不存在,此时fake-initial迁移过程会帮你全部创建,要么全部表都存在DB(不管表结果是否匹配),此时就跳过创建,不能只有一部分存在,那样会报错。(重点)
3. showmigrations
显示准备要迁移时将会执行哪些migrations包下的py文件,该命令会拿本地migrations包的py迁移文件跟DB的django_migrations表的记录相比较,缺少的就是要进行执行迁移动作的。比如以下,有X
标记的就是已经执行过的,空白的就是待要执行的。
vmaig_auth
[X] 0001_initial
[X] 0002_tourist
vmaig_comments
[ ] 0001_initial
vmaig_system
[X] 0001_initial
4. sqlmigrate
查看某个App下的迁移文件(譬如0002_auto_20190315_2052.py)对应翻译出来的sql语句,不真正对数据库操作,仅显示打印语句。
usage: manage.py sqlmigrate [-h] [--version] [-v {0,1,2,3}]
[--settings SETTINGS] [--pythonpath PYTHONPATH]
[--traceback] [--no-color] [--database DATABASE]
[--backwards]
app_label migration_name
Prints the SQL statements for the named migration.
合并/重置migration
不再需要原有DB中的数据
这个好办,可以把整个库都删除掉,和把所有App内migrations包里的数字开头的py文件全删(包括0001_initial.py),ini.py要保留; 然后就从头来生成一次并迁移即可。
python manage.py makemigrations
python manage.py migrate
在原有数据基础上重置
这个时候预先最好先做了备份。
1. 先确保当前DB表结构和项目模型定义已同步,即所有需要迁移的动作都已在DB上已执行。
>python manage.py makemigrations
No changes detected
>python manage.py migrate
Running migrations:
No migrations to apply.
- 把要重置的App内migrations包里的数字开头的py文件全删(包括0001_initial.py),ini.py要保留;
- 重新生成新的迁移文件。
>python manage.py makemigrations
...
0001_initial.py:
- Create model Comment
其实到这里已经OK了,已实现了迁移文件合并到0001_initial.py来,并且Model和DB也是同步的。
4. 如果想迁移记录表瘦下身的话,手动去删除DB里django_migrations表里的对应App下所有记录;再进行一次fake迁移即可。
delete from django_migrations where app="myapp1";
>python manage.py migrate --fake
可以了,这里用–fake和–fake-initial都可以。
migrations包是否需要版本git提交
有些人说要传git,但我个人觉得不需要把migrations push到git或svn。有初始创建和模型更新的时候只提代py代码,线上或其他开发者只需要fetch py代码,然后执行makemigrations
和migrate
就行,因为django框架会自己检查DB和Model生成本地迁移文件,这样还能避免产生过多的py迁移文件。