makemigrations未生成迁移文件是因为Django未识别到模型变更,常见原因包括:app未注册、模型未继承models.Model、类名以下划线开头、字段拼写错误、类型写成字符串、文件未保存或编辑错误环境。

makemigrations 为什么没生成迁移文件
常见现象是改了 models.py,运行 python manage.py makemigrations 却提示 “No changes detected”。本质不是命令失效,而是 Django 没识别到模型变更。
典型原因有:
-
INSTALLED_APPS里没注册对应 app(哪怕目录存在、__init__.py存在也不行) - 模型类没继承
models.Model,或类名以_开头被当成内部类忽略 - 字段名拼错、类型写成字符串(如
CharField写成"CharField"),导致导入失败,Django 静默跳过该模型 - 修改后没保存文件,或编辑的是错误分支/虚拟环境下的文件
验证方法:运行 python manage.py showmigrations 看当前已记录的迁移状态;再用 python -c "from myapp.models import MyModel; print(MyModel._meta.db_table)" 确认模型能否正常导入。
migrate 报错 django.db.utils.ProgrammingError: relation "xxx" does not exist
这是最常卡住人的一步:迁移文件生成了,但 python manage.py migrate 失败,提示某张表不存在。根本原因不是 SQL 错误,而是 Django 迁移系统内部状态和数据库实际结构不一致。
立即学习“Python免费学习笔记(深入)”;
常见触发场景:
- 手动删过数据库表,但没同步删除
django_migrations表里的记录 - 多人协作时,有人直接执行了
migrate,有人跳过了某次迁移(比如用--fake或删了迁移文件) - 从生产库 dump 数据到本地后,没清空
django_migrations表,导致 Django 认为“这些迁移已执行”,实际表并不存在
临时解法(仅开发环境):python manage.py migrate --fake-initial 可跳过初始迁移;但更稳妥的是先查 SELECT * FROM django_migrations WHERE app = 'myapp';,再对比迁移文件名,手动删掉数据库里多出的记录,或补上缺失的迁移。
迁移文件里出现 dependencies 和 operations 是怎么来的
makemigrations 不是简单比对字段增删,而是基于模型历史快照做差异计算。每个迁移文件的 dependencies 字段,记录它依赖哪些其他迁移(通常是同一 app 的前一个迁移,或跨 app 的 auth、contenttypes 初始化迁移),确保执行顺序不乱。
operations 列表才是真实动作,比如:
-
AlterField:字段类型或 null 属性变了 -
AddField:新增字段(注意:非空字段必须提供default或设null=True,否则生成失败) -
CreateModel:首次建表 -
RemoveField:删字段(默认不真删,加--delete才生效)
如果手动改迁移文件里的 operations,Django 不会校验 SQL 合法性,但后续 migrate 很可能报错;改 dependencies 更危险——可能让迁移链断裂,建议用 python manage.py makemigrations --empty myapp 新建空迁移来打补丁。
为什么有时 migrate 不建表,有时又清空重来
Django 建表行为完全由迁移系统驱动,不是靠模型定义实时同步。关键点在于:migrate 只执行「尚未标记为已完成」的迁移,且每条迁移操作是否执行,取决于 django_migrations 表里的记录,而不是数据库里有没有那张表。
所以:
- 新项目第一次
migrate,会按顺序执行所有迁移,包括0001_initial.py创建表 - 已有项目新增模型,
makemigrations生成0002_add_user_profile.py,migrate只跑这一条,不会动旧表结构 - 但如果删掉
django_migrations表里所有记录,再migrate,Django 就会重新执行全部迁移——此时若旧表还存在,大概率因重复建表报错
真正危险的操作是:在未备份的情况下,手动删表 + 清空 django_migrations + 重跑 migrate。Django 不检查表是否存在,只管按迁移文件发 SQL,而 CreateModel 操作默认不含 IF NOT EXISTS,直接炸。










