Django数据库路由迁移报错:django_migrations表id列多默认值问题
尝试配置DATABASE ROUTER,将myapp应用的RedshiftModel路由至Redshift数据库,其余模型路由至PostgreSQL。执行命令python manage.py migrate --database redshift时,出现以下错误:
SyntaxError: multiple default values specified for column "id" of table "django_migrations"
ProgrammingError: multiple default values specified for column "id" of table "django_migrations"
MigrationSchemaMissing: Unable to create the django_migrations table (multiple default values specified for column "id" of table "django_migrations")
Redshift中尚未存在django_migrations表,怀疑路由的allow_migrate方法逻辑有误。相关代码如下:
路由代码(routers.py)
class DbRouter: def db_for_read(self, model, **hints): if model._meta.app_label == 'myapp': if model._meta.model_name == 'RedshiftModel': return 'redshift' else: return 'default' return None def db_for_write(self, model, **hints): if model._meta.app_label == 'myapp': if model._meta.model_name == 'RedshiftModel': return 'redshift' else: return 'default' return None def allow_relation(self, obj1, obj2, **hints): if obj1._meta.app_label == 'myapp' or obj2.app_label == 'myapp': return True return None def allow_migrate(self, db, app_label, model_name=None, **hints): if app_label == 'myapp': if model_name == 'RedshiftModel': return db == 'redshift' else: return db == 'default' return None
模型代码(models.py)
class RedshiftModel(models.Model): date = models.DateField(blank=True, null=True) class Meta: managed = False db_table = '"int". "redshift_table"' app_label = 'myapp'
数据库配置(settings.py)
DATABASES = { 'default': { 'ENGINE': 'django.db.backends.postgresql', 'NAME': os.environ.get('NAME'), 'USER': os.environ.get('USER'), 'PASSWORD': os.environ.get('PASSWORD'), 'HOST': os.environ.get('HOST'), 'PORT': os.environ.get('PORT'), }, 'redshift': { 'ENGINE': 'django_redshift_backend', 'NAME': os.environ.get('RDATABASE'), 'USER': os.environ.get('RUSER'), 'PASSWORD': os.environ.get('RPASSWORD'), 'HOST': os.environ.get('RHOST'), 'PORT': os.environ.get('RPORT'), 'OPTIONS': { 'options': '-c search_path=int' } } } DATABASE_ROUTERS = [ 'myproject.settings.routers.DbRouter' ]
1. 核心问题分析
错误根源是django_redshift_backend在创建django_migrations系统表时,对id列生成了重复的默认值定义,导致Redshift无法创建该表。另外,你的RedshiftModel设置了managed = False,意味着Django不会为它生成迁移文件,也不需要对Redshift执行migrate操作——因为该模型对应的表已经在Redshift中存在。
2. 修复路由的allow_migrate方法
当前路由未处理Django系统表的迁移逻辑,导致执行migrate --database redshift时,Django尝试在Redshift创建系统表。修改allow_migrate方法,明确禁止在Redshift上执行任何迁移:
def allow_migrate(self, db, app_label, model_name=None, **hints): # 禁止所有迁移操作在redshift数据库执行 if db == 'redshift': return False # myapp的非RedshiftModel迁移到default库 if app_label == 'myapp': return db == 'default' # 其他app的迁移按默认逻辑处理 return None
3. 正确操作流程
- 对PostgreSQL(default库)执行正常迁移:
python manage.py migrate RedshiftModel是managed=False,无需生成迁移文件,直接在代码中使用即可,不要对Redshift执行migrate命令。
额外优化点
- 模型中的
db_table可简化写法,去掉转义字符,直接使用:
db_table = '"int"."redshift_table"'
- 路由的读写方法可简化逻辑,无需嵌套判断:
def db_for_read(self, model, **hints): if model._meta.app_label == 'myapp' and model._meta.model_name == 'RedshiftModel': return 'redshift' return 'default' def db_for_write(self, model, **hints): return self.db_for_read(model, **hints)
内容的提问来源于stack exchange,提问作者facepet

