Django自定义User模型与多数据库配置异常排查求助
问题核心
自定义认证应用authentication,配置双数据库:auth_db负责auth、contenttypes、authentication应用数据,主库负责其余业务应用。已完成auth_db的模型迁移,通过--database=auth_db创建超级用户并成功登录后台,但在后台创建业务对象时抛出IntegrityError:django_admin_log表外键约束违规,提示user_id=1不存在于authentication_user表中。
排查与解决步骤
1. 检查数据库路由是否覆盖admin应用
django_admin_log属于django.contrib.admin应用,若路由规则未将其指向auth_db,admin日志会默认写入主库,而主库中不存在authentication_user表的对应数据,直接触发外键错误。
打开databases_router.py,确认route_app_labels包含admin:
class AuthRouter: # 必须将'admin'加入路由标签列表 route_app_labels = {'auth', 'contenttypes', 'authentication', 'admin'} def db_for_read(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'auth_db' return None def db_for_write(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'auth_db' 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 == 'auth_db' return db == 'default' # 主库标识,需与settings.py中一致
2. 验证admin应用的迁移归属
执行命令检查django.contrib.admin的迁移是否在auth_db中完成:
# 查看auth_db中admin的迁移状态 python manage.py showmigrations admin --database=auth_db # 查看主库中admin的迁移状态 python manage.py showmigrations admin --database=default
如果主库存在admin的迁移记录,先回滚:
python manage.py migrate admin zero --database=default
再在auth_db中执行admin迁移:
python manage.py migrate admin --database=auth_db
3. 排查Celery进程的数据库配置
Celery Beat/Worker若未正确加载Django配置,可能跳过路由规则直接使用默认数据库:
- 确认Celery启动命令正确指定settings:
celery -A 你的项目名 beat -l info --settings=你的项目名.settings - 在Celery任务中添加日志验证数据库路由:
执行任务后,若日志显示使用主库,说明Celery未正确应用路由规则,需检查启动环境变量或配置文件加载逻辑。from django.db import connections from celery import shared_task import logging logger = logging.getLogger(__name__) @shared_task def check_db_route(): from django.contrib.admin.models import LogEntry from authentication.models import User # 打印LogEntry和User模型使用的数据库 logger.info(f"LogEntry 数据库: {connections[LogEntry.objects.db].settings_dict['NAME']}") logger.info(f"User 模型数据库: {connections[User.objects.db].settings_dict['NAME']}")
4. 验证请求上下文的数据库路由
在admin视图中临时添加调试代码,确认当前请求的数据库指向:
# 在任意业务模型的admin.py中添加 from django.contrib.admin.models import LogEntry from django.db import connections class YourModelAdmin(admin.ModelAdmin): def save_model(self, request, obj, form, change): # 打印LogEntry和当前用户的数据库 print(f"LogEntry 写入数据库: {connections[LogEntry.objects.db].settings_dict['NAME']}") print(f"当前用户所在数据库: {request.user._state.db}") super().save_model(request, obj, form, change)
若输出显示LogEntry使用主库,检查settings.py中DATABASE_ROUTERS配置是否正确:
DATABASE_ROUTERS = ['你的项目名.databases_router.AuthRouter']
确保路由类路径无拼写错误。
5. 确认用户数据的数据库归属
在Django Shell中验证当前用户是否来自auth_db:
python manage.py shell
执行代码:
from authentication.models import User user = User.objects.get(id=1) print(user._state.db) # 应输出'auth_db'
若输出非auth_db,检查路由类的db_for_read方法是否正确处理authentication应用。
内容的提问来源于stack exchange,提问作者Florent

