Множественные миграции Django Postgres: "Миграции не применяются"
Настройка: одна база данных Postgres с двумя схемами: "по умолчанию" и "другие". С помощью:
Django==2.0.10
psycopg2-binary==2.7.7
(нет бинарной версии в производстве)
Моя конфигурация базы данных:
DATABASES = {
'default': {
'ENGINE': 'django.db.backends.postgresql',
'OPTIONS': {
'options': '-c search_path=django,default',
},
...
'TEST': {
'NAME': 'default',
'DEPENDENCIES': ['other'],
},
'ATOMIC_REQUESTS': True,
},
'other': {
'ENGINE': 'django.db.backends.postgresql',
'OPTIONS': {
'options': '-c search_path=other,default',
},
...
'TEST': {
'NAME': 'other',
'DEPENDENCIES': [],
},
'ATOMIC_REQUESTS': True,
}
}
Шаги, сделанные на новой базе данных:
py manage.py migrate
: работает должным образом, и схема "по умолчанию" переносится правильно.py manage.py migrate --database=other
результаты в:No migrations to apply.
Как ни странно, выполнение этих шагов (опять же, в новой базе данных) в обратном порядке работает:
py manage.py migrate --database=other
: работает как положено, и "другая" схема переносится правильно.py manage.py migrate
Результат: работает как положено, и схема "по умолчанию" переносится правильно.
Я подозреваю, что это как-то связано с django_migrations
Таблица. Я не знаю много об этой таблице, есть ли один на схему Postgres? Или есть только один django_migrations
таблица на проект? После долгих поисков я увидел много предложений по использованию маршрутизаторов баз данных. "Другая" схема должна иметь все те же таблицы, что и схема "по умолчанию", поэтому маршрутизатор в этом случае не поможет.
Я пытался выполнить SQL DELETE FROM django_migrations
после запуска миграций по умолчанию и затем выполнения миграций по другому; это работает только для первой миграции на новую базу данных, любые последующие попытки миграции приводят к ошибке, так как Django пытается применить уже примененные миграции и вызывает django.db.utils.ProgrammingError: relation "<relation>" already exists
,
Я также пытался поиграть с django.db.migrations.recorder.MigrationRecorder
класс для очистки таблицы миграции между миграцией базы данных "по умолчанию" и "другая", опять же не повезло.
Кроме того, единственный способ, которым я смог запустить свой набор тестов, состоял в том, чтобы установить "other" как зависимость для "default", чтобы использовать странный факт, что миграция "other" до "default" работает.
Я в недоумении относительно того, почему это происходит, я уверен, что что-то мне не хватает.
Обновить
Предпринимаем те же шаги, что и ранее:
py manage.py migrate
: работает должным образом, и схема "по умолчанию" переносится правильно.py manage.py migrate --database=other
результаты в:No migrations to apply.
После нескольких копаний в pgAdmin я запустил следующий SQL
SET search_path TO default
SELECT * FROM django_migrations
и это вернуло таблицу прикладных миграций, как и ожидалось. Затем запустить следующий SQL
SET search_path TO other
SELECT * FROM django_migrations
и я получил сообщение о том, что отношение "django_migrations" не существует. Так что это отвечает на мой вопрос относительно django_migrations
таблица: должна быть одна на схему, и это, конечно, имеет смысл.
Так что это заставляет меня думать, что Джанго, должно быть, смотрит на django_migrations
таблица из схемы "по умолчанию" при попытке перенести "другую" схему и, таким образом, видит, что "миграции не применяются". Я буду продолжать пытаться решить эту проблему, любые указатели будут иметь большое значение, так как я все еще не уверен, как заставить миграции работать на обеих схемах.
Обновить
Я написал это как ответ, но это решение работало только локально, поэтому я добавил его вместо обновления.
Посмотрев на DATABASES
Конфигурация на некоторое время я наконец понял, что вызывает проблемы, которые я видел. Я предоставил список через запятую для каждого search_path
вариант вроде так:
DATABASES = {
'default': {
...
'OPTIONS': {
'options': '-c search_path=django,default',
},
...
},
'other': {
...
'OPTIONS': {
'options': '-c search_path=other,default',
},
...
}
}
Моя интерпретация происходящего здесь: при беге py manage.py migrate
на свежей базе данных Django увидит, что нет django_migrations
таблицы в схеме "по умолчанию", создайте ее и затем заполните, когда она применяет миграции. Затем, когда я бегу py manage.py migrate --database=other
это будет выглядеть в "другом" для django_migrations
, не найти его, и тогда он должен выглядеть по умолчанию, так как это следующее место для поиска в пути поиска. Как django_migrations
уже существует в схеме "по умолчанию", Django будет использовать эту таблицу, а затем увидит, что "миграции не применяются". Возможно, я здесь не совсем точен, пожалуйста, поправьте меня, если я сказал что-то явно неправильное.
Изменение путей поиска в DATABASES
Конфигурация вроде так:
DATABASES = {
'default': {
...
'OPTIONS': {
'options': '-c search_path=default',
},
...
},
'other': {
...
'OPTIONS': {
'options': '-c search_path=other',
},
...
}
}
привел к успешной миграции обеих схем в моей локальной среде. Однако это не работает, когда миграции выполняются на TravisCI или Heroku. Оба из них дают эту ошибку при миграции либо "по умолчанию", либо "другое":
Traceback (most recent call last):
File "/home/travis/virtualenv/python3.6.3/lib/python3.6/site-packages/django/db/backends/utils.py", line 83, in _execute
return self.cursor.execute(sql)
psycopg2.ProgrammingError: no schema has been selected to create in
LINE 1: CREATE TABLE "django_migrations" ("id" serial NOT NULL PRIMA...
1 ответ
Решение моих проблем состоит из двух частей.
Получение миграции для работы на TravisCI
После обнаружения невероятной функции поиска репозитория GitHub я искал любое использование CREATE SCHEMA <schema_name>
в любой .travis.yml
файл.
Я изменил эти две строки в before_script
из моего .travis.yml
файл из
- psql -c "CREATE DATABASE travisci;" -U postgres
- psql -c "CREATE SCHEMA other;" -U postgres
в
- psql -c "CREATE DATABASE travisci;" -U postgres
- psql -c "CREATE SCHEMA other;" -d travisci -U postgres
Добавление -d travisci
Аргумент привел к корректной миграции обеих схем.
Заставить мигрантов работать на Heroku
Я использовал эту команду для доступа к клиенту SQL для моего приложения Heroku:
heroku pg:psql -a <app_name>
Для меня должно было быть очевидно, почему это не сработает. Вы можете иметь более одной базы данных для приложения Heroku, и я не указал имя базы данных. Использование этой команды сработало:
heroku pg:psql <database_name> -a <app_name>
Также с помощью pgAdmin работало создание схемы.