1

セットアップ: 'default' と 'other' の 2 つのスキーマを持つ 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 スキーマごとに 1 つありますか? django_migrationsそれとも、プロジェクトごとに 1 つのテーブルしかありませんか? 多くのグーグル検索の後、データベースルーターの使用に関する多くの提案を見ました。「他の」スキーマには、「デフォルト」スキーマと同じテーブルがすべて含まれている必要があるため、この場合、ルーターは役に立ちません。

DELETE FROM django_migrations「デフォルト」で移行を実行し、「その他」で移行を実行した後、SQL を実行しようとしました。これは、新しいデータベースでの最初の移行に対してのみ機能し、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ます。スキーマごとに1つある必要があり、これはもちろん完全に理にかなっています。

django_migrationsしたがって、これは、「他の」スキーマを移行しようとするときに、Django が「デフォルト」スキーマのテーブルを参照している必要があるため、「適用する移行が存在しない」と判断することにつながります。私はこれを解決しようとし続けます。両方のスキーマで移行を機能させる方法がまだわからないので、ポインタは大いに役立ちます。

アップデート

これを回答として書いたのですが、このソリューションはローカルでしか機能しなかったため、代わりに更新として追加しました。

しばらく構成を見つめた後、DATABASES私が目にしていた問題の原因をようやく理解しました。search_path次のように、各オプションにコンマ区切りのリストを提供しました。

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

ここで何が起こっているかについての私の解釈:新しいデータベースで実行すると、Djangoは「デフォルト」スキーマにテーブルpy manage.py migrateがないことを確認し、テーブルを作成してから、移行を適用するときにデータを入力します。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