【问题标题】:Django Postgres Multiple Schema Migrations: "No migrations to apply"Django Postgres 多模式迁移:“没有要应用的迁移”
【发布时间】:2019-06-23 21:46:20
【问题描述】:

设置:一个具有两种模式的 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 类来在迁移“默认”和“其他”数据库之间刷新迁移表,再次失败。

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

我不知道为什么会发生这种情况,我确定我缺少一些东西。

更新

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

  • 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 在尝试迁移“其他”模式时必须查看“默认”模式中的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...

【问题讨论】:

    标签: python django postgresql migration multiple-schema


    【解决方案1】:

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

    让迁移在 TravisCI 上工作

    在发现 GitHub 令人难以置信的 repo 搜索功能后,我在任何 .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 创建架构有效。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-06-24
      • 2016-04-14
      • 1970-01-01
      • 2018-10-24
      • 2022-11-10
      • 2020-10-14
      • 1970-01-01
      • 2019-12-24
      相关资源
      最近更新 更多