运维咖啡吧

享受技术带来的乐趣,体验生活给予的感动

Django生产环境不同APP之间Model迁移

在Django中,APP是应用程序Application的缩写。一个Django项目可以由多个APP组成,每个APP代表一个特定的功能模块或组件。合理的APP组织能够提高代码的可维护性和可复用性,随着项目的不断壮大,APP也不断的增多,难免会发现之前的Model组织不是十分合理,因此有了在不同APP之间迁移Model的需求。这篇文章就介绍下生产环境下如何在不同APP之间迁移Model

Django在不同APP之间迁移Model官方没有提供特别简单的方法,我们就采用最基础的方式:复制原APP下的Model到目标APP->修改所有Model引用->将原表里的数据同步至目标表->删除原Model

前期准备

在线上拉取代码执行变更操作之前的步骤都算是前期准备,前期准备最重要的事情就是修改代码,以下操作会在开发者本地执行

  1. 复制原APP下的Model到目标APP

在这一步中我们尽量保证Model内的所有字段一致,复制到新的Model后执行makemigrationsmigrate应用变更,如果无报错再进行下一步,有报错先解决报错,大多数报错可能都是因为外键引用Foreignkey引起的,例如我遇到的报错HINT: Add or change a related_name argument to the definition for 'carrier.OpsCoffee.content_type' or 'cruiser.OpsCoffee.content_type',为Foreignkey字段content_type添加related_name参数可解决

复制原APP下的Model到目标APP之后,建议删除原APP下Model中关于权限permissions的配置,这样可以在后续测试中保证不会再用到旧的Model,同时也为后续权限变更提供方便

  1. 修改所有Model引用

所有引用原APP下Model的地方都要改成从新的APP内引用,这一步较为繁琐,但如果用到一些IDE有提示Model引用位置的话会简单很多,例如我用的Pycharm会在Class上显示当前Class的引用次数,通过这里能很轻松的找到并修改所有引用原APP下Model的位置

除了model引用之外,如果有用到Django默认的权限系统,那么model对应的权限也要跟着修改,主要是view和template里的权限配置需要修改所对应的APP

  1. 迁移数据测试

迁移数据直接将原表数据导出,然后再新的表里导入即可,如果使用MySQL作为数据库,可以通过以下语句将原表src_ops_coffee内地数据迁移至目标表dst_ops_coffee

insert into dst_ops_coffee select * from src_ops_coffee;

以上语句有个前提是原表src_ops_coffee和目标表dst_ops_coffee字段要一模一样,包括字段位置,当字段不同时,可以通过如下语句操作

insert into dst_ops_coffee (id, create_time, update_time, instance_id, instance_name, instance_state) select id, create_time, update_time, instance_id, instance_name, instance_state from src_ops_coffee;

数据迁移完成就可以本地测试了,测试无异常就可以合并代码到更新到线上

在线迁移

迁移过程需要数据同步等操作,所以应在系统维护的时间段进行,先停止项目,然后开始正式的数据迁移操作

  1. 开始之前务必先备份数据库备份数据库备份数据库

  2. 拉取更新代码

  3. 应用数据库变更

python3 manage.py makemigrations
python3 manage.py migrate

这一步会有大量的数据库变更,属于正常情况。如果有Foreignkey外键依赖,可能会有foreign key constraint fails的报错,主要是因为新表里没有数据导致的,此时我们只需要进行下一步迁移数据即可,等迁移数据完成,再来执行migrate即可顺利完成

  1. 迁移数据库数据

在前期准备中的迁移数据测试阶段已经迁移过数据,同样的SQL在生产环境再次执行即可

  1. 调整权限

Django里的权限配置是跟APP相关的,例如模板权限perms.carrier.ops_coffee_change中的carrier就是APP名称,用到Django默认的权限系统的话,在迁移完成后需要做相应的权限调整

即便是你在原始的Model里删除了权限配置,Django的migrate也不会同步删除权限表auth_permission的对应的数据,所以此时需要手动删除,一般是以codename为条件过滤,删除ID较小的那个即可,如果不放心则可以拿content_type_id去Model记录表django_content_type确认Model

  1. 启动项目

以上工作做完后,就可以正常启动项目,测试并交付使用了

后续操作

以上操作完成可以正常使用,但此时原Model还未删除,原数据库表也还存在,可以保持这个状态运行一段时间,若无异常则可以删除原Model,同步至线上应用数据库更新,彻底删掉原数据库表,至此一个完整的Model迁移工作结束