Django-cms添加editor.js后迁移报CHECK constraint failed错误
错误产生原因
报错核心为字段类型与存量数据不匹配:
集成editor.js过程中,通常需要将存储普通文本的字段修改为JSONField类型,用来存储editor.js输出的结构化块内容,本次报错就是将sub_title字段改为JSON类型时触发的。
SQLite执行字段类型变更时会重建全表、拷贝原有存量数据,3.38及以上版本的SQLite会自动为JSON字段添加检查约束:要求字段值必须为合法JSON格式,或值为NULL。当前数据库中已存储的sub_title值均为普通纯文本,不符合JSON格式校验规则,数据拷贝阶段直接触发约束失败,导致迁移中断。
可行修复方案
根据实际场景选择对应方案即可:
- 本地开发环境、存量数据无保留价值
直接删除本地SQLite数据库文件,删除advita应用下migrations目录中除__init__.py外的所有迁移文件,重新执行python manage.py makemigrations和python manage.py migrate,从零构建表结构即可绕过存量数据校验问题。 - 生产/测试环境、需要保留存量数据
推荐拆分迁移步骤处理,避免数据丢失:- 先将迁移回滚到报错版本的上一版,执行命令:
python manage.py migrate advita 0002(0002替换为实际环境中0003之前最后一个执行成功的迁移版本号) - 不要直接修改原字段类型,先在模型中新增一个允许为空的JSONField临时字段(比如命名为
sub_title_new),执行python manage.py makemigrations和python manage.py migrate完成字段新增 - 编写数据迁移逻辑,遍历所有存量记录,把原有
sub_title字段里的纯文本内容转换成符合业务要求的合法JSON结构(比如封装为{"text": "原副标题文本"}的格式),写入新增的临时字段 - 生成新的迁移文件:删除原有的
sub_title字段,将临时字段重命名为sub_title,配置好对应字段约束(比如是否允许为空),执行迁移即可完成字段类型切换,不会触发约束报错。
- 先将迁移回滚到报错版本的上一版,执行命令:
- 不需要保留原有sub_title数据、追求快速修复
回滚迁移后,进入Django shell执行数据清理,将所有记录的sub_title值统一设为NULL或者合法JSON空值(比如空字典{}、JSON格式的空字符串),清理完成后重新执行触发报错的迁移文件即可。
注意:该问题和editor.js本身、Django框架bug无关,只要是将存储非JSON内容的字段修改为JSONField类型,无论使用SQLite、PostgreSQL还是MySQL,都会触发同类数据校验错误,本质原因是存量数据不符合字段类型约束。
内容的提问来源于stack exchange,提问作者vv2006-mc
相关产品推荐
相关产品推荐

