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() на экземпляре.

Это запустило миграцию и устранило проблему!

Вернуться на верх