Django多数据库配置后执行createsuperuser报缺少ENGINE值错误如何解决
错误原因
- 数据库路由缺失
db_for_write方法,且重复定义db_for_read:两个路由类中均重复定义了两次读路由逻辑,完全没有实现写操作的路由规则,Django处理写请求时无法匹配到对应数据库,就会默认路由到default库,而你的default库为空配置,直接触发报错。 allow_migrate方法返回值不符合规范:该方法要求返回布尔值(True/False/None)表示是否允许在指定数据库执行迁移,你直接返回了数据库名字符串,导致路由判断逻辑完全失效,迁移和运行时的路由匹配都会出错。- 自定义用户管理器保存逻辑冲突:你在
create_user中手动指定了using="users_db",但create_superuser调用完create_user后又执行了一次user.save(using=self._db),这里的self._db如果没有正确初始化,会落到默认库;同时从报错回溯可以看到create_user中实际执行的是不带using参数的user.save(),说明实际运行代码的保存参数被覆盖,进一步导致路由匹配失效。
解决方案
1. 修正数据库路由代码
删除重复的db_for_read定义,新增db_for_write方法,同时修正allow_migrate的返回值:
class AuthRouter: route_app_labels = {'sessions', 'auth', 'contenttypes', 'admin', 'accounts'} def db_for_read(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'users_db' return None # 新增写路由逻辑 def db_for_write(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'users_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): # 仅当数据库为users_db且应用属于路由列表时才允许迁移 if app_label in self.route_app_labels: return db == 'users_db' return None class PersonalDBRouter: route_app_labels = {'actions', 'blog', 'token_blacklist', 'taggit', 'django_celery_beat', 'django_celery_results',} def db_for_read(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'content_db' return None # 新增写路由逻辑 def db_for_write(self, model, **hints): if model._meta.app_label in self.route_app_labels: return 'content_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 == 'content_db' return None
2. 修正自定义用户管理器的保存逻辑
避免重复保存,统一指定保存的数据库:
class MyAccountManager(BaseUserManager): def create_user(self, email, username, first_name, last_name, password=None): if not email: raise ValueError('Users must have an email address') if not username: raise ValueError('Users must have a username') if not first_name: raise ValueError('Users must have a First Name') user = self.model( email=self.normalize_email(email), username=username, first_name=first_name, last_name=last_name, ) user.set_password(password) return user def create_superuser(self, email, username, first_name, last_name, password): user = self.create_user( email=self.normalize_email(email), password=password, username=username, first_name=first_name, last_name=last_name, ) user.is_admin = True user.is_staff = True user.is_superuser = True # 统一指定保存到users_db,也可以依赖路由自动匹配 user.save(using="users_db") return user
3. 可选兜底方案
如果调试阶段还是出现路由匹配问题,可以临时把default库指向users_db,避免路由失效时落到空库,等所有逻辑调试通顺后再改回空配置即可:
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'users_db', 'USER': 'postgres', 'PASSWORD': 'Trial_user123', 'HOST':'127.0.0.1', 'PORT':'5432', }, 'users_db': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'users_db', 'USER': 'postgres', 'PASSWORD': 'Trial_user123', 'HOST':'127.0.0.1', 'PORT':'5432', }, 'content_db': { 'ENGINE': 'django.db.backends.postgresql_psycopg2', 'NAME': 'content_II', 'USER': 'postgres', 'PASSWORD': 'Trial_user123', 'HOST':'127.0.0.1', 'PORT':'5432', }, }
内容的提问来源于stack exchange,提问作者Danny
相关产品推荐
相关产品推荐

