关于Python Django migrate、makemigra...

【现象】

https://www.jianshu.com/p/8d0463e25f35

终极方式是备份数据库删除原来的,创建一个空的再来migrate,随后还原数据,步骤如下:

  1. 步骤一:进入到iotos_mysql容器内,备份数据库,删除并重新创建

mysqldump -uroot -pIotos12345678 iotos_paas > iotos_paas.sql mysql>drop database iotos_paas; mysql>create database iotos_paas;

  1. 步骤二:到iotos_paas中,/home/iotos-paas-v2/中,执行migrate

1)一般情况下,我们是这样逐个操作(在各个应用下都没有此前生成的migrations目录文件时)

手动:iot、account、drive、video、margin、alert、scada

python3 makemigrations xxx; python3 migrate xxx;

自动:admin、auth、contenttypes、sessions,

python3 makemigrations; python3 migrate;

但是实际反而这种操作,导致数据库表字段ORM有整改变动,反而django mirgate出各种错!


2)实际测试发现,iotos-paas-v2中,从空数据库构建完整数据库表结构ORM,全局操作即可(在各个应用下已经有了此前生成的migrations目录文件时):

  • python3 manage.py makemigrations;
  • python3 manage.py migrate;

(或者指定某个应用比如account,效果也是一样的)

然后验证数据库中指定表的某个字段是否如期创建:describe iotos_paas.scada_scada;

修改了某个表结构或字段增改,比如scada_scada表,也只需要全局migrate即可,不需要指定特定Django App:

  • python3 manage.py makemigrations;
  • python3 manage.py migrate;

  1. 步骤三:到iotos_mysql中,还原数据库:

mysql -uroot -pIotos12345678 iotos_paas < iotos_paas.sql;


【重要】找到了Django ORM migrate经常失败,提示数据库XXX表已存在的根本原因了!!

分为几种情况:

  1. 空库+不空migrations

以下全局操作migrate即可,表都会自动生成,不再需要每个APP单独migrate,因为里面migrations目录都在,直接操作全局的就好:

  • python3 manage.py makemigrations;
  • python3 manage.py migrate;
  1. 非空库+不空migrations

mysql还原sql导入到数据库非空时,对此前的migrations基础上migrate会报错,提示xxx表已存在,去掉一个还有一个,所有表都报已存在!!

  1. 非空库+空migrations

全局migrate无错误提示,但是没有任何效果(绿色ok);针对具体APP来migrate,提示相应APP的XX表已存在!

  1. 空库+空migrations

全局migrate报错,提示要基于APP进行migrate;逐个APPmigrate生成没问题!


【方案一】保持表结构能migrate,并且导入的数据只有当前修改了表结构的才会清空,其他都保留在

  • 开发环境无所谓,不需要业务数据,出现任何问题,删除数据库重新创建就好!对新的镜像发不出去,生产环境数据库还原覆盖就好(除非数据库结构大变,导致还原覆盖的数据结构字段,系统不再兼容导致无法运行!)
  • 生产环境主要是保护当前数据,而且经常涉及到数据库数据的备份和导入,只要存在mysql导入sql备份文件,基本就别指望改环境下django orm migrate能再正常运行,所以更新生产环境只有跟开发环境一样只是注意数据先备份、再创建新数据库,再要做备份的数据还原!
  • 问题是数据库备份文件的还原,都对数据库结构也进行了还原,那么本地开发ORM更新的字段、新的数据库结构呢?程序还怎么正常运行识别字段??migrate app的时候后面加上zero参数,那么会单独清空当前APP的数据库表,然后就可以构建了:python3 manage.py migrate scada zero只是这种情况下,当前表的内容会被清空(删除表、重建)!(虽然会导致当前应用的表单独删除重建导致清空,但是总比mysql全部数据和表结构覆盖过来的好)

【附】Django项目的APP下面的migrations目录非常重要,不是临时文件!如果随意删除或者git没有同步,拉取下来想要在mirgate,就会一堆报错和坑!

https://www.kawabangga.com/posts/1789

Django的Model是按照每次的migrations管理(即app下的migrations包)的。每次更新Model之后,都需要先运行python manage.py makemigrations进行生成migration,这些migrations中记录了数据库的变更,然后用python manage.py migrate应用这些更改。

随着项目的增大,migrations也越来越多,每次新的migration都是基于前一次的,也就是说,每次更改数据库,都要把所有的migration走一遍。导致执行migrate的时候速度很慢。比如我们公司的仓库,每次migrate需要二十多分钟。大哥说可以删掉所有的migrations,重新生成,然后用migrate –fake命令“假装执行”,这样做一次,后面的操作都变快了。

今天,我想在自己的项目上用这个方法,于是照着大哥的方法做了遍。本地没有任何问题,做好之后,去服务器操作。结果挂了。服务器的错误如下:

试过很多办法,甚至把本地的数据库都删掉,也无济于事。

其中的一个尝试让我发现,服务器revert回去,先执行makemigrations,服务器没问题,然后git拉到本地,本地竟然出现了同样的问题。

尼玛,坑爹呢这是。

我打开migrations文件,看了看有个叫做('auth', '0008_auto_20160710_0926')的依赖,本地找不到。在项目里面全局搜了一下,也没搜到这个文件。关于Python Django migrate、makemigra..._第1张图片

 

最后用pycharm全局搜了一下,找到了…… 从pycharm的颜色可以看出,这并不是在项目中的一个文件,而是site-package的文件,竟然也有migrations,好坑啊……

从git diff可以看出,主要是文件名字的结尾不同。django生成migrations文件的明明规则是次数+内容+时间的。这个不同得从我管理项目的方式说起。我觉得migrations文件不是项目代码的一部分(不是自动生成的),所以将migrations文件夹放到了gitignore中。每次更新数据库,本地做本地的migrations,服务器做服务器的。这样,就造成时间不同,本地是09:26,服务器是10:04,两个文件名字不一样……所以有了上文的冲突。

比较好的解决方法是:用git连migrations一起管理着,服务器只执行migrate。说不定什么时候我们还需要手动修改生成的migrations呢!

瞎忙活了一下午,给我的教训是……不要手忙脚乱,认真看报错的信息,慢慢推理吧!慌什么呢!

教训2:还是实践让人学习啊,应该用git管理migrations而不是教给django去生成就行了。


【方案二】(终极方案)导入进来的数据和表结构都在,并且能后续migrate修改表结构(新增字段可以、修改字段名称发现不起效果)

不仅仅是解决数据库备份还原导入后无法migrate,同时也是解决任何时候mirgate报错的恢复机制!

https://zhuanlan.zhihu.com/p/55440044

默认此时已经mysql导入了sql覆盖还原了数据库,现在开始

  1. 步骤一:展示所有Django APP的migration状态

这里可以看到项目本身的应用:iot、account、drive、video、margin、alert、scada,只要有migrations目录的都会列出来,此外还有django内部的app,比如这里admin!且其migrations目录在django的安装包目录里!问题隐藏非常深,并不在项目目录!

python3 manage.py showmigrations

关于Python Django migrate、makemigra..._第2张图片

 

  1. 步骤二:对自身APP及1中列的系统APP(admin)逐个依次以下步骤操作
  • 如果1中没有比如account,需要首先对其makemigrations,然后showmigrations就能看到了,系统APP包含:admin、contenttypes、auth、sessions(实测发现,其中只有admin需要手动如下操作,其他几个不需要管)
  • 重点注意内置应用django_admin,需要find / 全盘查找到django安装目录去删除migrations内文件(0001_initial文件名都一样,那就用第二三个名称logentry等这些,就能查到目录在哪一并删掉:find / -name "*0002_logentry_remove_auto_add*")
  1. python3 manage.py showmigrations //这步可以省去,查看各APP的migration状态
  1. python3 manage.py makemigrations XXX //这步可以省去,如果已经有migrations目录就不需要,而且只要在showmigrations中有看到,那么肯定就是有migrations目录的!
  1. python3 manage.py migrate --fake XXX zero //这步必不可少
  1. rm -rf ./account/migrations/0001_initial.py //这步必不可少,所有000X的多个都删掉
  1. rm -rf ./account/migrations/__pycache__ //这个目录也删掉,只保留__init__.py
  1. python3 manage.py makemigrations account //这步必不可少
  1. python3 manage.py migrate account --fake-initial //这步必不可少

所有APP都经过这些步骤后,就可以全局mirage了:

  1. python3 manage.py makemigrations //后续单个APP有ORM更新,都只需要操作全局这两步就好
  1. python3 manage.py migrate

  1. 注意:还有两个问题,初始变动不同步以及删除报错

以scada为例,本地原始数据库ORM字段结构,并且按照这个结构在平台有导出数据,同时现在对原始ORM结构有修改,包括修改了某个字段名、新增了某个字段。

mysql把前面导出的数据还原,并且经过本方案二做到可以migrate同时不丢失数据。只是初始的这个makemigrations、migrate,并不会把scada本地更新后的ORM同步上去,还是旧的,看着好像没变!

实际上,需要对ORM文件再做修改,才能被识别有变动,再进行全局makemigratioins和migrate,就可以新增、修改以及删除字段,包括批量新增、批量修改、批量删除都可以!

关于Python Django migrate、makemigra..._第3张图片  关于Python Django migrate、makemigra..._第4张图片

 

  • 只是千万要注意,在做fake zero、fake-initial过程中,应用的ORM可能已经新增或者修改了字段,在fake完毕全局migrate时,这些字段不会被更新到数据库,跟没变化一样!
  • 本地新增、以及对新增的修改和删除,都能在下一次(全局)migrate中,都能同步到数据库去,前面fake期间的字段还是一样不会被带上去。
  • 非但无法通过修复的migrate把前面的更新到数据库去,反而如果删除或者修改这些字段会报错!因为数据库结构跟本地已经不一致了!要删除能生效,除非手动修改migrations里面的文件,把涉及这几个字段的操作都给删除或者屏蔽掉!本地删除就好,数据库里本来就没有,你通过migrate提交到数据库去修改、删除又是想起个什么作用??

关于Python Django migrate、makemigra..._第5张图片

 

 

你可能感兴趣的:(django,python,后端)