1

设置:一个具有两种模式的 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每个项目只有一张桌子?经过大量谷歌搜索后,我看到了许多关于使用数据库路由器的建议。“其他”模式必须与“默认”模式具有所有相同的表,因此在这种情况下路由器将无济于事。

DELETE FROM django_migrations在“默认”上运行迁移然后在“其他”上运行迁移后,我尝试执行 SQL ;这仅适用于新数据库上的第一次迁移,任何后续迁移尝试都会导致错误,因为 Django 尝试应用已应用的迁移并 raises django.db.utils.ProgrammingError: relation "<relation>" already exists

我还尝试过使用django.db.migrations.recorder.MigrationRecorder该类来在迁移“默认”和“其他”数据库之间刷新迁移表,再次没有运气。

此外,我能够让我的测试套件运行的唯一方法是将“其他”设置为“默认”的依赖项,以利用在“默认”之前迁移“其他”有效的奇怪事实。

我不知道为什么会这样,我确定我缺少一些东西。

更新

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

  • 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表的问题:每个模式应该有一个,这当然很有意义。

因此,这使我认为 Djangodjango_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...
4

1 回答 1

0

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

让迁移在 TravisCI 上工作

在发现 GitHub 令人难以置信的 repo 搜索功能后,我搜索了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 上工作

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

heroku pg:psql -a <app_name>

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

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

还使用 pgAdmin 创建架构有效。

于 2019-01-30T23:49:07.177 回答