背景、问题与正确解决方案
随着项目的长期迭代,Django ORM 的字段结构会不断变化:
- 某些字段被删除 / 重命名
- 新字段被添加
- 外键约束变化
- 表结构由迁移文件自动维护
而 现在线上的旧数据库结构仍然停留在历史版本,它的字段与当前 Django 的模型不一致。
当我们要把旧数据库的数据迁移到最新 Django 版本时,就会面临:
- 老库的字段结构和新库不一致
- Django 的系统表(auth_*, django_migrations 等)在每个版本中都不同
- 部分旧表在新版本中已不存在
- 新版本 Django 期望由 migrations 自动创建表结构,而不是用旧 SQL 覆盖
从旧数据库导出sql,不包含表结构和django系统表和不存的表
因此,传统数据库迁移方法 完全行不通
传统方法为什么失败?
mysqldump 导出 SQL → mysql < sql 导入到新数据库 → 再 migrate 报错
arduino
django.db.utils.OperationalError: (1054, "Unknown column 'xxx' in 'django_migrations'")
原因:表结构不一致导致 migrate 报错
- 新 Django 模型删除了某个字段
- 旧 SQL 仍然包含该字段
- migrate 无法正确应用迁移,因为数据库结构被旧 SQL 覆盖了
先 migrate(数据库迁移)→ 再导入 SQL 报错
rust
ERROR 1136 (21S01): Column count doesn't match value count at row 1
ERROR 1062 (23000): Duplicate entry '1' for key 'auth_permission.PRIMARY'
ERROR 1146 (42S02): Table 'new_db.xxx' doesn't exist
原因:数据结构不匹配、重复插入 Django 系统表,旧 SQL 包含 Django 系统表(auth_permission 等),旧 SQL 中存在新项目中已删除的表
正确解决方案(推荐)
由 Django 决定新结构(migrate),旧数据库只迁移业务数据(无结构)
- mysqldump导出旧数据库,不包含表结构,不导出 Django 系统表,新数据库没有的表,使用
--complete-insert确保字段名对应
ini
mysqldump -uroot -p old_db \
-t --skip-triggers \
--complete-insert \
--ignore-table=old_db.auth_permission \
--ignore-table=old_db.auth_group \
--ignore-table=old_db.auth_group_permissions \
--ignore-table=old_db.auth_user \
--ignore-table=old_db.auth_user_groups \
--ignore-table=old_db.auth_user_user_permissions \
--ignore-table=old_db.django_content_type \
--ignore-table=old_db.django_admin_log \
--ignore-table=old_db.django_migrations \
--ignore-table=old_db.django_session \
--ignore-table=old_db.你的app_你的模型 \
> data_only.sql
-
数据库迁移
python manage.py migrate
这一过程由 Django 自动完成:
- 创建最新结构
- 添加新字段
- 删除旧字段
- 创建所有 Django 系统表
- 维护外键约束
- 导入旧数据到新数据库
css
mysql -uroot -p 新数据库 < data_only.sql