ポイント1に最も近い同様のことを行いましたが、ミドルウェアを使用してデフォルトの接続を設定する代わりに、Djangoデータベースルーターが使用されます。これにより、アプリケーションロジックは、リクエストごとに必要に応じて、多数のデータベースを使用できます。すべてのクエリに適したデータベースを選択するのはアプリケーションロジック次第であり、これがこのアプローチの大きな欠点です。
この設定では、すべてのデータベースがsettings.DATABASES
に一覧表示されます。 、顧客間で共有される可能性のあるデータベースを含みます。顧客固有の各モデルは、特定のアプリラベルを持つDjangoアプリに配置されます。
例えば。次のクラスは、すべての顧客データベースに存在するモデルを定義します。
class MyModel(Model):
....
class Meta:
app_label = 'customer_records'
managed = False
データベースルーターはsettings.DATABASE_ROUTERS
に配置されます app_label
によってデータベースリクエストをルーティングするチェーン 、このようなもの(完全な例ではありません):
class AppLabelRouter(object):
def get_customer_db(self, model):
# Route models belonging to 'myapp' to the 'shared_db' database, irrespective
# of customer.
if model._meta.app_label == 'myapp':
return 'shared_db'
if model._meta.app_label == 'customer_records':
customer_db = thread_local_data.current_customer_db()
if customer_db is not None:
return customer_db
raise Exception("No customer database selected")
return None
def db_for_read(self, model, **hints):
return self.get_customer_db(model, **hints)
def db_for_write(self, model, **hints):
return self.get_customer_db(model, **hints)
このルーターの特別な部分は、thread_local_data.current_customer_db()
です。 電話。ルーターを実行する前に、呼び出し元/アプリケーションは、現在の顧客データベースをthread_local_data
に設定しておく必要があります。 。この目的でPythonコンテキストマネージャーを使用して、現在の顧客データベースをプッシュ/ポップできます。
これらすべてを構成すると、アプリケーションコードは次のようになります。UseCustomerDatabase
現在の顧客データベース名をthread_local_data
にプッシュ/ポップするコンテキストマネージャーです。 そのため、thread_local_data.current_customer_db()
ルーターが最終的にヒットしたときに正しいデータベース名を返します:
class MyView(DetailView):
def get_object(self):
db_name = determine_customer_db_to_use(self.request)
with UseCustomerDatabase(db_name):
return MyModel.object.get(pk=1)
これはすでにかなり複雑な設定です。それは機能しますが、私が見ている長所と短所を要約してみます:
利点
- データベースの選択は柔軟です。 1つのクエリで複数のデータベースを使用でき、リクエストでは顧客固有のデータベースと共有データベースの両方を使用できます。
- データベースの選択は明示的です(これが長所か短所かはわかりません)。顧客データベースにヒットするクエリを実行しようとしたが、アプリケーションがクエリを選択しなかった場合、プログラミングエラーを示す例外が発生します。
- データベースルーターを使用すると、
USE db;
に依存するのではなく、さまざまなデータベースをさまざまなホストに存在させることができます。 すべてのデータベースが単一の接続を介してアクセス可能であると推測するステートメント。
短所
- セットアップは複雑で、機能させるにはかなりの数のレイヤーが必要です。
- スレッドローカルデータの必要性と使用法はあいまいです。
- ビューにはデータベース選択コードが散らばっています。これは、ミドルウェアがデフォルトのデータベースを選択するのと同じ方法で、リクエストパラメータに基づいてデータベースを自動的に選択するために、クラスベースのビューを使用して抽象化できます。
- データベースを選択するコンテキストマネージャーは、クエリの評価時にコンテキストマネージャーが引き続きアクティブになるように、クエリセットをラップする必要があります。
提案
柔軟なデータベースアクセスが必要な場合は、Djangoのデータベースルーターを使用することをお勧めします。ミドルウェアまたはビューMixinを使用して、要求パラメーターに基づいて接続に使用するデフォルトのデータベースを自動的にセットアップします。使用するデフォルトのデータベースを格納するためにスレッドローカルデータに頼らなければならない場合があります。これにより、ルーターがヒットしたときに、どのデータベースにルーティングするかがわかります。これにより、Djangoはデータベース(必要に応じて別のホストに存在する場合があります)への既存の永続的な接続を使用でき、リクエストで設定されたルーティングに基づいて使用するデータベースを選択します。
このアプローチには、 QuerySet using()
デフォルト以外のデータベースを選択する機能。