Django多库分片场景下迁移失败及只读库配置问题求助
问题解决方案
问题根源分析
migrate无响应:当前路由的allow_migrate方法对非tracking应用返回None,Django默认会尝试在default数据库执行这些迁移,但你要求default数据库只读且原有迁移已完成;同时tracking应用的迁移未明确指定目标库,导致未被执行。- 指定database_tracking迁移报错:Django尝试在database_tracking中执行系统应用(如
django.contrib.contenttypes)的迁移,但该数据库未初始化这些系统表,因此出现django_content_type不存在的错误。
具体解决步骤
1. 修正数据库路由规则
更新TrackingRouter的allow_migrate方法,明确各应用的迁移权限:
class TrackingRouter: route_app_labels = {'tracking'} # 系统应用列表,禁止在database_tracking执行迁移 system_app_labels = {'django.contrib.admin', 'django.contrib.auth', 'django.contrib.contenttypes', 'django.contrib.sessions', 'django.contrib.messages', 'django.contrib.staticfiles', 'django.contrib.postgres'} # 禁止迁移的自定义应用(authentication模型为非托管) no_migrate_apps = {'authentication'} def db_for_read(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'database_tracking' return None def db_for_write(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'database_tracking' 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): # 禁止authentication应用的任何迁移操作 if app_label in self.no_migrate_apps: return False # tracking应用仅允许在database_tracking执行迁移 if app_label in self.route_app_labels: return db == 'database_tracking' # 系统应用禁止在任何数据库执行迁移(原有应用已完成default库的系统表初始化) if app_label in self.system_app_labels: return False # 其他应用默认禁止迁移 return False
2. 生成并执行tracking应用的迁移
首先确保tracking应用已生成迁移文件:
python manage.py makemigrations tracking
然后仅针对database_tracking执行tracking应用的迁移(避免触发系统应用迁移):
python manage.py migrate tracking --database database_tracking
3. 排除authentication应用的迁移
由于authentication.User设置了managed=False,需避免为其生成迁移:
- 删除已生成的authentication应用迁移文件(如果有)
- 后续执行
makemigrations时排除该应用:
python manage.py makemigrations --exclude authentication
4. 配置admin面板的用户模型
在authentication/admin.py中注册User模型,确保admin能正常读取default库的用户数据:
from django.contrib import admin from .models import User admin.site.register(User)
5. 加固default数据库的只读权限
从数据库层面设置只读用户,彻底避免误操作:
针对MySQL执行以下SQL:
CREATE USER 'readonly_user'@'%' IDENTIFIED BY 'your_secure_password'; GRANT SELECT ON your_default_db_name.* TO 'readonly_user'@'%'; FLUSH PRIVILEGES;
然后在settings.py的DATABASES['default']中使用该只读用户的 credentials。
验证流程
- 执行
python manage.py migrate tracking --database database_tracking,确认无错误,且database_tracking中生成了tracking应用的表 - 启动Django服务,尝试登录admin,确认能使用原有用户正常登录
- 测试tracking应用的读写功能,确认操作均指向database_tracking
内容的提问来源于stack exchange,提问作者Anuj TBE
相关产品推荐
相关产品推荐

