1つのテーブル「django_migrations」のみを使用して、Djangoで複数のデータベースを使用します


11

Djangoのプロジェクトでは、デフォルトリモートの 2つのデータベースを使用する必要があります。私が作成しrouters.py、すべてが正常に動作します。

リモートデータベースにテーブルを作成する必要があり、移行を作成して実行し、テーブルdjango_migrationsを作成しました。django_migrationsデフォルトのデータベースに、テーブルを1つだけ含めたいです。

の関連部分routers.pyはここにあります:

class MyRouter(object):
     # ...
     def allow_migrate(self, db, app_label, model_name=None, **hints):
         if app_label == 'my_app':
             return db == 'remote'
         return None

私はこのように移行を実行します:

python manage.py migrate my_app --database=remote

今私がするとき:

python manage.py runserver

次の警告が表示されます。

未適用の移行が1つあります。アプリの移行を適用するまで、プロジェクトは正常に機能しない可能性があります:my_app。
それらを適用するには、「python manage.py migrate」を実行します。

のテーブルmy_appremoteデータベースに作成され、データベースdjango_migrations内でremote移行が適用済みとしてマークされます。

編集:
Djangoに強制的に1つのテーブルのみを使用django_migrationsさせ、それでも移行を別のデータベースに適用する方法は?

警告が発生しないように移行を異なるデータベースに適用する方法は?


1
「my_app」ではない他のアプリの場合、allow_migrateはNoneを返します。たぶん、そこで別のチェックをしたいですか?ルーターから私が理解していることから、「my_app」は「リモート」データベースを使用し、他のすべてのアプリは「デフォルト」データベースを使用しますか?
Martin Taleski、

@cezarあなたはほとんど不可能を求めます。django_migrationsテーブルを共有するためには、移行のための行defaultremotedb を区別する必要があります。これは、djangoの内部のかなり深いところにあります。移行コードの大幅な書き直しが必要になると私は言ってもリスクを冒します。
Kamil Niski、

@KamilNiskiご意見をお寄せいただきありがとうございます。質問を書き直します。
セザール

この問題は関連している可能性があります。
Kevin Christopher Henry

回答:


2

私の質問に対するコメントのおかげで、私はいくつかの調査を行い、以下の発見を思いつきました。

複数のデータベースを使用するとdjango_migrations、移行の使用時にテーブルが作成されます。Kamil Niskiのdjango_migrationsコメントで説明されているように、移行を1つのテーブルのみに記録するオプションはありません。これはファイルを読んだ後は明らかですdjango/db/migrations/recorder.py

プロジェクトfoobarプロジェクト内のアプリの例を示します。アプリのbarモデルは1つだけですBaz

プロジェクトを作成します。

django-admin startproject foo

これで、これらのコンテンツがメインプロジェクトディレクトリ内にあります。

- foo
- manage.py

プロジェクトディレクトリ内のすべてのアプリをグループ化する習慣があります。

mkdir foo/bar
python manage.py bar foo/bar

このファイルでfoo/settings.pyは、この例の目的のために、2つの異なるデータベースを使用するように設定を調整しますsqlite3

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db1.sqlite3'),
    },
    'remote': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': os.path.join(BASE_DIR, 'db2.sqlite3'),
    }
}

次に、マイグレーションを実行します。

python manage.py migrate --database=default

これはすべての移行を実行します --database=defaultます。指定しない場合、Djangoはデフォルトのデータベースを使用するためはオプションです。

実行する操作:
  すべての移行の適用: admin、auth、contenttypes、session
 実行中の移行:
  contenttypes.0001_initialを適用しています... OK
  auth.0001_initialを適用しています... OK
  admin.0001_initialを適用しています... OK
  admin.0002_logentry_remove_auto_addを適用しています... OK
  admin.0003_logentry_add_action_flag_choicesを適用しています... OK
  contenttypes.0002_remove_content_type_nameを適用しています... OK
  auth.0002_alter_permission_name_max_lengthを適用しています... OK
  auth.0003_alter_user_email_max_lengthを適用しています... OK
  auth.0004_alter_user_username_optsを適用しています... OK
  auth.0005_alter_user_last_login_nullを適用しています... OK
  auth.0006_require_contenttypes_0002を適用しています... OK
  auth.0007_alter_validators_add_error_messagesを適用しています... OK
  auth.0008_alter_user_username_max_lengthを適用しています... OK
  auth.0009_alter_user_last_name_max_lengthを適用しています... OK
  auth.0010_alter_group_name_max_lengthを適用しています... OK
  auth.0011_update_proxy_permissionsを適用しています... OK
  セッションを適用しています。0001_initial... OK

Djangoはすべての移行をデフォルトのデータベースに適用しました:

1 contenttypes 0001_initial 2019-11-13 16:51:04.767382
2 auth 0001_initial 2019-11-13 16:51:04.792245
3管理者0001_initial 2019-11-13 16:51:04.827454
4管理者0002_logentr 2019-11-13 16:51:04.846627
5管理者0003_logentr 2019-11-13 16:51:04.864458
6 contenttypes 0002_remove_ 2019-11-13 16:51:04.892220
7 auth 0002_alter_p 2019-11-13 16:51:04.906449
8 auth 0003_alter_u 2019-11-13 16:51:04.923902
9 auth 0004_alter_u 2019-11-13 16:51:04.941707
10 auth 0005_alter_u 2019-11-13 16:51:04.958371
11 auth 0006_require 2019-11-13 16:51:04.965527
12 auth 0007_alter_v 2019-11-13 16:51:04.981532
13 auth 0008_alter_u 2019-11-13 16:51:05.004149
14 auth 0009_alter_u 2019-11-13 16:51:05.019705
15 auth 0010_alter_g 2019-11-13 16:51:05.037023
16 auth 0011_update_ 2019-11-13 16:51:05.054449
17セッション0001_initial 2019-11-13 16:51:05.063868

次に、モデルを作成しますBaz

models.py

from django.db import models

class Baz(models.Model):
    name = models.CharField(max_length=255, unique=True)

アプリbarINSTALLED_APPSfoo/settings.py)に登録し、移行を作成します。

python manage.py makemigrations bar

移行を実行する前に、routers.py内部で作成しますbarアプリ。

クラスBarRouter(オブジェクト):
    def db_for_read(self、model、** hints):
        if model._meta.app_label == 'bar':
            「リモート」を返す
        戻り値なし

    def db_for_write(self、model、** hints):
        if model._meta.app_label == 'bar':
            「リモート」を返す
        戻り値なし

    def allow_relation(self、obj1、obj2、** hints):
        戻り値なし

    def allow_migrate(self、db、app_label、model_name = None、** hints):
        app_label == 'bar'の場合:
            db == 'remote'を返す
        db == 'remote'の場合:
            Falseを返す
        戻り値なし

そしてそれを登録してfoo/settings.pyください:

DATABASE_ROUTERS = ['foo.bar.routers.BarRouter']

今の素朴なアプローチはbarremoteデータベースへの移行を実行することです:

python manage.py migrate bar --database=remote
操作は実行する:
  すべてのマイグレーションを適用します。バー
 の移行の実行します:
  bar.0001_initialを適用しています... OK

移行がremoteデータベースに適用されました:

1小節0001_initial 2019-11-13 17:32:39.701784

実行すると:

python manage.py runserver

次の警告が発生します。

未適用の移行が1つあります。アプリの移行を適用するまで、プロジェクトが正しく機能しない可能性があります:バー。
それらを適用するには、「python manage.py migrate」を実行します。

すべてがうまくいくようですが。ただし、この警告が表示されるだけでは不十分です。

この回答で提案されているように、適切な方法は、各データベースのすべての移行を実行することです。

次のようになります。

python manage.py migrate --database=default
python manage.py migrate --database=remote

の移行を作成した後bar

python manage.py migrate bar --database=default
python manage.py migrate bar --database=remote

ルーターはテーブルbar_bazremoteデータベースにのみ作成されるように注意しますが、Djangoは移行を両方のデータベースに適用されるものとしてマークします。また、、、などのテーブルはauthadminで指定されているようsessionsに、defaultデータベースにのみ作成されrouters.pyます。データベースのテーブルにdjango_migrationsは、remoteこれらの移行のレコードも含まれます。

それは長い読み物ですが、私の意見では、公式ドキュメントで問題を完全に説明していないので、これについていくつかの光が当てられることを願っています

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.