Django项目执行migrate等迁移命令时终端挂起问题排查

问题现象
- 单个Django项目执行所有数据库迁移相关命令(
migrate、makemigrations)时终端直接挂起无响应,同环境下其他Django项目运行均正常。 - 因项目无有效业务数据,曾彻底删除
db.sqlite3文件、所有应用下migrations目录内的全部迁移文件,首次执行migrate时依然挂起——此时命令已经重新生成了空的db.sqlite3文件。 - 单独对任意应用执行
makemigrations可以正常生成0001_initial.py初始迁移文件并返回ok状态,但后续执行migrate时会提示无待执行的新迁移,命令始终无法正常退出,必须按**ctrl-c**强制中断进程。 - 曾等待数十分钟,命令始终处于挂起状态,无任何报错输出。
已定位的触发规则
排查确认问题和根路由配置直接相关,对应配置代码如下:
urlpatterns = [ path('admin/', admin.site.urls), #path('clink/', include('clink.urls')), path('', include('searchnet.urls')), ]
- 只要取消注释启用
clink应用的路由规则,就会导致searchnet应用的迁移操作挂起。 clink应用内未定义任何数据模型,也从未执行过迁移操作,仅在searchnet的index.html模板中存在一个指向clink普通落地页的链接,无其他复杂业务逻辑。
根因说明
这个问题是Django管理命令的启动加载逻辑和路由链路中的阻塞代码冲突导致的:
Django执行migrate、makemigrations这类管理命令时,会先完整加载项目配置的根路由文件,递归加载所有include()引入的子路由、对应依赖的模块,这个加载流程在迁移逻辑执行之前就会跑完。只要路由加载链路上任意位置存在阻塞逻辑,就会卡住整个命令进程,和clink应用有没有模型、有没有迁移记录没有关系。
常见触发场景:
clink/urls.py中导入的视图、工具模块里,在函数/类外层(模块导入时就会执行的位置)写了数据库查询代码,比如直接在文件顶层写xxx = Model.objects.all()这类语句。迁移命令启动时数据库表还没完成初始化/迁移,这类查询会一直等待数据库响应,直接卡住进程。clink/urls.py存在循环引用配置,比如不小心include了根路由文件、或者include了自身,导致路由加载时进入无限递归。clink应用的apps.py里ready()方法写了阻塞逻辑,比如未做兼容的数据库查询、死循环、未设超时的外部资源请求,应用加载时自动执行就会卡住。- 路由对应导入的模块顶层存在无限循环、死锁代码。
修复步骤
- 打开
clink/urls.py,逐行检查所有import的模块,把所有写在顶层的数据库操作、IO请求、循环逻辑全部移到视图函数/类方法内部,确保模块导入阶段不会执行任何需要等待资源的逻辑。 - 检查clink应用的路由配置,删掉错误的循环include规则。
- 检查clink应用的
apps.py、__init__.py文件,把ready()方法、顶层代码里的阻塞逻辑移走,或者加上迁移环境判断:如果当前执行的是迁移命令,直接跳过这类逻辑。 - 如果clink只是承载单页落地页、没有复杂逻辑,可以不用单独创建应用,直接把模板放到现有searchnet应用下配普通路由映射即可,从根源上避免加载额外模块带来的问题。
内容的提问来源于stack exchange,提问作者TechnoDiver
相关产品推荐
相关产品推荐

