Django多数据库路由配置后指定库执行migrate仅第二位库生效问题
Django多数据库迁移顺序异常问题解决方案
问题根因
你的问题出在数据库路由的allow_migrate方法返回值规则错误,符合Django路由的执行逻辑:
Django会按DATABASE_ROUTERS列表的顺序逐个调用路由的对应方法,只要某一个路由返回了非None的明确值,后续路由就不会再执行该方法的判断。
你当前两个路由的allow_migrate逻辑中,只要应用不属于自身管辖范围,直接返回False(明确禁止迁移),而非返回None(转交判断权给下一个路由),就会导致排在后面的路由永远没有机会判断自身管辖的应用迁移权限:
- 当路由顺序为
[DMSRouter, CredRouter]时:判断cred应用的迁移请求会先走到DMSRouter,直接返回False禁止迁移,不会再执行CredRouter的判断逻辑,因此cred_db无法迁移 - 调换路由顺序后逻辑同理,只有排在前面的路由对应的数据库可以正常迁移
修复方案
步骤1:修改所有自定义路由的allow_migrate返回值
将不属于当前路由管辖的应用的返回值从False改为None,转交判断权给后续路由。
修改后的DMSRouter示例:
from django.conf import settings class DMSRouter: route_app_labels = ["dms"] def db_for_read(self, model, **hints): if model._meta.app_label in self.route_app_labels: return settings.DMS_DB_ROUTER return None def db_for_write(self, model, **hints): if model._meta.app_label in self.route_app_labels: return settings.DMS_DB_ROUTER return None def allow_relation(self, obj1, obj2, **hints): if ( obj1._meta.app_label in self.route_app_labels or obj2._meta.app_label in self.route_app_labels ): return True return None def allow_migrate(self, db, app_label, model_name=None, **hints): if app_label in self.route_app_labels: return db == settings.DMS_DB_ROUTER # 不属于当前路由管辖的应用,转交判断权给下一个路由 return None
CredRouter做同样修改,仅将最后一行的return False改为return None即可。
步骤2:(可选但推荐)迁移时明确指定应用
为了避免公共应用迁移混乱,迁移时建议明确指定对应的应用名:
# 生成迁移文件 python manage.py makemigrations cred dms # 迁移default库(如果default库有需要迁移的应用) python manage.py migrate # 迁移cred应用到cred_db python manage.py migrate cred --database=cred_db # 迁移dms应用到dms_db python manage.py migrate dms --database=dms_db
后续多库扩展规范
后续接入新的独立数据库应用时,只需要遵循两个规则即可无需调整顺序:
- 每个新应用的自定义路由,非自身管辖范围的所有方法都返回
None - 按接入顺序把新路由加到
DATABASE_ROUTERS列表末尾即可
内容的提问来源于stack exchange,提问作者Aagam Sheth
相关产品推荐
相关产品推荐

