MySQL迁移PostgreSQL后驼峰列名转小写致Django ORM列不存在报错
问题最优解决方案
按实施成本从低到高、长期维护性从好到差排序,优先选择第一种方案:
方案1:修正PostgreSQL端的列名,零改动兼容现有代码(首选)
问题根源是pgloader默认迁移时不会给标识符加双引号,而PostgreSQL对未加双引号的标识符会自动转为全小写存储,最终把原驼峰格式的列名全部转成了小写。直接修正数据库端的命名,不需要改动任何分散在各处的业务代码,一次操作彻底解决问题。
- 如果还没切流量、可以重跑迁移:修改pgloader配置文件,加上
quote identifiers配置项,让pgloader迁移时给所有表名、列名加双引号,强制PG保留原驼峰格式的标识符,参考配置:
LOAD DATABASE FROM mysql://your_mysql_user:your_password@mysql_host/source_db_name INTO postgresql://your_pg_user:your_password@pg_host/target_db_name WITH quote identifiers, create tables, create indexes, reset sequences, foreign keys;
重跑迁移后,PG里的列名会和原MySQL完全一致,比如brochureName会原样保留,Django ORM的查询可以直接正常运行。
- 如果已经完成迁移、不想重跑全量数据:直接批量重命名PG里的列,给列名加上双引号保留驼峰格式。可以先从源MySQL库的
information_schema.COLUMNS中导出所有表对应的原驼峰列名,批量生成ALTER TABLE语句执行,单条重命名语法参考:
ALTER TABLE brochure RENAME COLUMN brochurename TO "brochureName";
执行完所有重命名语句后,数据库侧结构就和原MySQL完全匹配,不需要改任何业务代码。
方案2:数据库无法调整时,在Django模型层统一做映射(禁止零散改查询)
如果因为权限、流程原因无法修改PG的列结构,不要零散修改各处的查询语句,直接在Django模型层统一做字段映射,所有适配逻辑集中维护,避免漏改:
- 给所有驼峰命名字段显式指定
db_column参数,指向PG中实际存储的全小列明,示例:
class Brochure(models.Model): # 原字段定义保留,只加db_column映射到小写列 brochureName = models.CharField(max_length=255, db_column="brochurename") # 其余驼峰字段按同样规则加映射
- 字段数量多的话不需要逐个手动添加,可以写一个Django自定义元类或者批量扫描工具,自动读取模型字段名,将驼峰格式转成小写后自动注入
db_column参数,一次配置全模型生效。
避坑说明
不要尝试通过修改PostgreSQL全局参数、给每个查询语句硬加双引号、全局替换代码里的字段名为小写的方式解决问题:前两种方式会破坏数据库的默认行为,给后续升级、运维、第三方组件对接埋隐患;全局替换代码字段名的改造成本极高,很容易出现漏改、误改业务逻辑的问题,后续新增字段也容易重复踩坑。
内容的提问来源于stack exchange,提问作者Rohit Hazare
相关产品推荐
相关产品推荐

