Django Postgres 多模式迁移:"No migrations to apply"

Django Postgres Multiple Schema Migrations: "No migrations to apply"

设置:一个具有两个模式的 Postgres 数据库:'default' 和 'other'。使用:

我的数据库配置:

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,
    }
}

对新数据库采取的步骤:

奇怪的是,以相反的顺序执行这些步骤(再次在新数据库上)有效:

我怀疑这与 django_migrations table 有关。我不太了解这个 table,每个 Postgres 模式都有一个吗?或者每个项目只有一个 django_migrations table?经过大量谷歌搜索后,我看到了很多关于使用数据库路由器的建议。 'other' 架构必须具有与 'default' 架构完全相同的 table,因此在这种情况下路由器将无济于事。

我尝试在 'default' 运行ning 迁移之后执行 SQL DELETE FROM django_migrations,然后在 'other' 执行 运行ning 迁移;这仅适用于新数据库上的第一次迁移,任何后续迁移尝试都会导致错误,因为 Django 会尝试应用已经应用的迁移并引发 django.db.utils.ProgrammingError: relation "<relation>" already exists.

我也试过使用 django.db.migrations.recorder.MigrationRecorder class 刷​​新迁移 'default' 和 'other' 数据库之间的迁移 table,同样没有运气.

此外,我能够让我的测试套件达到 运行 的唯一方法是将 'other' 设置为 'default' 的依赖项,以利用迁移 'other' 在 'default' 工作之前。

我不知道为什么会这样,我确定我遗漏了什么。

更新

采取与前面提到的相同的步骤:

在 pgAdmin 中进行一些挖掘之后,我 运行 以下 SQL

SET search_path TO default
SELECT * FROM django_migrations

这按预期返回了 table 应用迁移。然后运行宁以下SQL

SET search_path TO other
SELECT * FROM django_migrations

我收到一条错误消息,指出关系 "django_migrations" 不存在。所以这回答了我关于 django_migrations table 的问题:每个模式应该有一个,这当然很有意义。

所以这让我认为 Django 在尝试迁移 'other' 模式时必须查看 'default' 模式中的 django_migrations table 并因此看到有 "no migrations to apply"。我会继续努力解决这个问题,任何指示都会有很长的路要走,因为我仍然不确定如何让迁移在两个模式上工作。

更新

我把它写成一个答案,但这个解决方案只在本地有效,所以我把它添加为更新。

盯着 DATABASES 配置一段时间后,我终于明白是什么导致了我所看到的问题。我为每个 search_path 选项提供了一个逗号分隔的列表,如下所示:

DATABASES = {
    'default': {
        ...
        'OPTIONS': {
            'options': '-c search_path=django,default',
        },
        ...
    },
    'other': {
        ...
        'OPTIONS': {
            'options': '-c search_path=other,default',
        },
        ...
    }
}

我对这里发生的事情的解释:当 运行ning py manage.py migrate 在新数据库上时,Django 会发现 django_migrations table 'default' 架构,创建一个,然后在应用迁移时填充它。然后当我 运行 py manage.py migrate --database=other 它会在 'other' 中寻找 django_migrations,找不到它然后它必须在 'default' 中寻找,因为它是下一个地方查看搜索路径。由于 django_migrations 已经存在于 'default' 模式中,Django 将使用此 table 然后看到有 "no migrations to apply"。可能我说的不完全准确,如有明显错误请指正。

像这样更改 DATABASES 配置中的搜索路径:

DATABASES = {
    'default': {
        ...
        'OPTIONS': {
            'options': '-c search_path=default',
        },
        ...
    },
    'other': {
        ...
        'OPTIONS': {
            'options': '-c search_path=other',
        },
        ...
    }
}

导致两个模式都在我的本地环境中成功迁移。但是,当在 TravisCI 或 Heroku 上迁移 运行 时,这不起作用。两者都在 'default' 或 'other':

迁移时给出此错误
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...

我的问题的解决方案分为两部分。

让迁移在 TravisCI 上工作

发现 GitHub 令人难以置信的回购搜索功能后,我在任何 .travis.yml 文件中搜索了 CREATE SCHEMA <schema_name> 的任何用法。

我将 .travis.yml 文件的 before_script 中的这两行从

更改为
- 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 上工作

我一直在使用此命令访问我的 Heroku 应用程序的 SQL 客户端:

heroku pg:psql -a <app_name>

我应该很清楚为什么这行不通。每个 Heroku 应用程序可以有多个数据库,我没有指定数据库名称。使用此命令有效:

heroku pg:psql <database_name> -a <app_name>

也可以使用 pgAdmin 创建模式。