0

自作の (ただし、利用可能なプラグイン メソッドに近い) マルチテナント実装を備えた Django アプリで、すべてのスキーマに適用できる South を使用して移行 (今回は単純な add_column) を実行したいと考えています。私はこれに非常に近い構成を持っています。

可能であれば、純粋な SQL クエリをスキップしたいと思います。ORM からスキーマ名のリストを適切に取得できますが、さまざまなスキーマから適切な方法でテーブルにアクセスする可能性があるかどうか疑問に思います。

DB_HOST と DB_SCHEMA をパラメーターを介してあるレベルで変更できるようにするためのフックがありますが、South の forwards migration メソッド内でこのようにきれいにループすることはできないと思います。

この質問はかなりハイレベルですが、誰かが同じ種類の質問に直面しなければならなかったのではないかと主に考えています。それを処理するための賢い方法があるかどうか知りたいです!

よろしく、マット

4

2 に答える 2

1

これは、Southメーリングリストに掲載されているソリューションの概要です。フレーズとしての質問は、リストに投稿されたものとは少し異なります。そこでは、すべてのテナント間で共有される「共通の」テーブルが別のスキーマにあることも言及されました。Rmatt自身の答えは、これをパブリックスキーマと呼んでいます。

私のソリューションの基本的な考え方:各データベース(スキーマ)の移行履歴をスキーマに保存します。これを行うには、データベースとDjangoのトリックを使用する必要があります。

これは、パブリックスキーマ上のアプリの移行の履歴レコードがパブリックスキーマに保存され、テナントアプリの移行の履歴がテナントスキーマに保存されることを意味します。つまり、移行履歴テーブルが効果的にシャーディングされます。Djangoはこの種のシャーディングを実際にはサポートしていません。インスタンスコンテンツごとに書き込みを設定するのは簡単ですが、読み取りを設定する方法はありません。

そこで、テナントごとに、パブリックスキーマとテナントスキーマsouth_migrationhistoryのテーブルを結合した、という名前の1つのビューを含む「テナントヘルパー」スキーマを作成することを提案しました。south_migrationhistory次に、South MigrationHistoryモデルのデータベースルーターをセットアップし、次のように指示します。

  • パブリックスキーマとテナントスキーマの両方へのsyncdb
  • テナントヘルパースキーマから常に読み取る
  • 移行が属するアプリに応じて、パブリックスキーマまたはテナントスキーマに書き込みます

その結果、テナントアプリの移行からパブリックアプリの移行への依存関係を適切に処理できます。migrate --allつまり、順方向に移行するために必要なのは、 (または)コマンドをループすることだけですsyncdb --migrate。逆方向の移行を偽造する必要はありません。パブリックスキーマの移行は、ループ内の最初のテナントの移行で実行され、他のすべてのテナントはそれらを「認識」します。

後から考えると、ヘルパースキーマがなくてもこれを行うことはおそらく可能ですsouth_migrationhistory。テナントスキーマのテーブルの名前を変更し、クエリ時に上記のユニオンを返すスキーマにその名前のビューをインストールし、「名前が変更されたテーブルに書き込むための「代わりに-挿入」トリガー。

于 2012-11-26T12:29:54.170 に答える
0

そうですね、この非常に特殊な問題を経験したり、心配したりする人はそれほど多くないようです。私はあちこちでいくつかのことを試しました。また、いくつかの点を理解するのに役立つサウス メーリング リストからのサポートも得ました。

基本的に、私が実装したソリューションは次のとおりです。

South のschemamigration によって自動生成されたごく普通の移行ファイルがあります。しかし、add_columndelete_columnのテーブル名を に変更しましたschema.table_name。スキーマは、マルチテナント ミドルウェアをインポートすることによって提供されます。

その後、移行は、スキーマがパブリックスキーマに対して実行されない場合にのみ適用されます。実際には、スタンドアロンで実行すること、またはデータベースとスキーマの kwargs のみを使用することを意図したものではなく、新しい django コマンドである移行ランナーから実行することを意図しています。

残念ながら、ランナーは、ミドルウェアを毎回通過するために、マイグレーションを外部で呼び出す必要があります。もう 1 つのトリックは、各テナントの移行後に南部の以前の状態に偽装するために、移行の以前の状態を取得する必要があることです。

ここに私のスニペットがあります:

from subprocess import call
import os
from django.core.management.base import BaseCommand    
from south.models import MigrationHistory
from myapp.models import MyModel

class Command(BaseCommand):

    def handle(self, *args, **options):
        #the only allowed arg is the prefix version and it should have a length of 4 (i.e. 0002)
        applied = MigrationHistory.objects.filter(app_name='myapp').latest('applied')
        current_version = applied.migration[:4]
        call_args = ['python', os.path.join('bin', 'manage.py'), 'migrate', 'myorderbird.app.backups']
        if len(args) == 1 and len(args[0]) == 4:
            call_args.append(args[0])

        obje_call_args = None
        for obje in MyModel.objects.all():
            if obje.schema_exists:
                # fake the migration of the previous venue back to the current version
                if obje_call_args:
                    obje_call_args = obje_call_args[:4] + [current_version, '--fake'] + obje_call_args[len(obje_call_args)-3:]
                    call(obje_call_args)
                # migrate the venue in the loop
                obje_call_args = list(call_args)
                obje_call_args.extend(['--database={}'.format(obje.db), '--schema={}'.format(obje.schema)])
                call(venue_call_args)
于 2012-11-23T17:28:04.040 に答える