django数据模型迁移的几个有用命令简介


简介

模型对象django内置了ORM,它在操作数据库时一般情况下无需直接写sql语句,而是用常规面向对象的方式调用模型对象的方法和属性,django框架底层会自动转为sql操纵数据库。 开发者要管理好这个ORM模型和DB的关系,背后需要理解几个django定义的几个有关迁移的命令。

  • makemigrations
  • migrate
  • showmigrations
  • sqlmigrate

迁移原理

关于迁移原理有4个点先介绍下

  1. 模型model类代码
  2. App下的migrations包(文件夹)
  3. DB里的django_migrations表
  4. 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文件,表示已执行过了,并能清楚看到执行时间。
migrations

命令说明

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.
  1. 把要重置的App内migrations包里的数字开头的py文件全删(包括0001_initial.py),ini.py要保留;
  2. 重新生成新的迁移文件。
>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代码,然后执行makemigrationsmigrate就行,因为django框架会自己检查DB和Model生成本地迁移文件,这样还能避免产生过多的py迁移文件。

/latefirstcmt/9