Django-tenants "Невозможно создать таблицу django_migrations".
Возникла проблема, когда наша производственная база данных не переносилась из-за ошибки во время миграции. Эта ошибка была связана с использованием пакета django-tenants
, который является развилкой пакета django-tenant-schemas
.
Ошибка:
Traceback (most recent call last):
File "/backend/manage.py", line 21, in <module>
main()
File "/backend/manage.py", line 17, in main
execute_from_command_line(sys.argv)
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 419, in execute_from_command_line
utility.execute()
File "/usr/local/lib/python3.9/site-packages/django/core/management/__init__.py", line 413, in execute
self.fetch_command(subcommand).run_from_argv(self.argv)
File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 354, in run_from_argv
self.execute(*args, **cmd_options)
File "/usr/local/lib/python3.9/site-packages/django/core/management/base.py", line 398, in execute
output = self.handle(*args, **options)
File "/usr/local/lib/python3.9/site-packages/django_tenants/management/commands/migrate_schemas.py", line 89, in handle
executor.run_migrations(tenants=tenants)
File "/usr/local/lib/python3.9/site-packages/django_tenants/migration_executors/standard.py", line 14, in run_migrations
Starting new HTTPS connection (1): o1380729.ingest.sentry.io:443
run_migrations(self.args, self.options, self.codename, schema_name, idx=idx, count=len(tenants))
File "/usr/local/lib/python3.9/site-packages/django_tenants/migration_executors/base.py", line 45, in run_migrations
migration_recorder.ensure_schema()
File "/usr/local/lib/python3.9/site-packages/django/db/migrations/recorder.py", line 70, in ensure_schema
raise MigrationSchemaMissing("Unable to create the django_migrations table (%s)" % exc)
django.db.migrations.exceptions.MigrationSchemaMissing: Unable to create the django_migrations table (relation "django_migrations" already exists
)
Что может вызвать эту ошибку?
Тот факт, что несколько арендаторов мигрировали до возникновения ошибки, говорит о том, что ошибка вызвана конкретным арендатором. Чтобы определить, откуда взялась ошибка, нам нужно проследить обратную трассировку. В предпоследней строке мы видим:
File "/usr/local/lib/python3.9/site-packages/django_tenants/migration_executors/standard.py", line 14, in run_migrations
Starting new HTTPS connection (1): o1380729.ingest.sentry.io:443 run_migrations(self.args, self.options, self.codename, schema_name, idx=idx, count=len(tenants))
File "/usr/local/lib/python3.9/site-packages/django_tenants/migration_executors/base.py", line 45, in run_migrations migration_recorder.ensure_schema()
File "/usr/local/lib/python3.9/site-packages/django/db/migrations/recorder.py"
Итак, заглянув в исходный код django_tenants
в районе 45-й строки /usr/local/lib/python3.9/site-packages/django_tenants/migration_executors/base.py
, мы видим такой код:
connection = connections[options.get('database', get_tenant_database_alias())]
connection.set_schema(schema_name, tenant_type=tenant_type)
# ensure that django_migrations table is created in the schema before migrations run, otherwise the migration
# table in the public schema gets picked and no migrations are applied
migration_recorder = MigrationRecorder(connection)
migration_recorder.ensure_schema() # line 45
Поскольку schema_name
передается в connection.set_schema(schema_name, tenant_type=tenant_type)
, мы можем подняться на одну строку вверх и поместить оператор print, чтобы вывести имя схемы, на которую выполняется миграция. Этот оператор print будет отображаться на консоли во время миграций и показывать схему, в которой возникла проблема. В нашем случае это было вызвано тем, что дублирующиеся имена схем были разрешены из-за разной капитализации в именах схем.
Для изменения имени схемы мы зашли в оболочку Django, используя python manage.py shell
, импортировали модель арендатора, вызвали instance = TenantModel.objects.get(schema_name="conflicting_name")
и установили схему на другое имя, используя instance.schema_name("new_name")
и вызвали instance.save()
на экземпляре.
Это запустило миграцию и устранило проблему!