1. ホーム
  2. postgresql

[解決済み] SQLAlchemyによるPostgresスキーマのサポート

2023-05-05 14:16:04

質問

SQLAlchemy と postgres を使ってマルチテナントのアプリをホストしています。私は、各テナントのために別々のデータベースを持つことから、複数のスキーマを持つ単一のデータベースに移行することを検討しています。SQLAlchemyはこれをネイティブにサポートしていますか?私は基本的に、すべてのクエリに、あらかじめ決められたスキーマを付加したいだけです。

select * from client1.users

ではなく、単に

select * from users

あちこちのテーブルだけでなく、特定のリクエスト/リクエストのセットのすべてのテーブルのスキーマを切り替えたいことに注意してください。

私はこれがカスタムクエリクラスで同様に達成されることを想像しますが、何かがすでにこの静脈で行われていないとは想像できません。

どのように解決するのですか?

これにはいくつかの方法があり、アプリがどのように構成されているかに依存します。 ここでは、最も基本的な方法を紹介します。

meta = MetaData(schema="client1")

あなたのアプリの実行方法が、アプリケーション全体の中で一度に1つの "クライアント"である場合、あなたは終了します。

しかし、ここで間違っているかもしれないのは、そのMetaDataからのすべてのTableがそのスキーマ上にあることです。 1 つのアプリケーションで複数のクライアントを同時にサポートしたい場合 (通常、quot; multitenant" の意味)、MetaData のコピーを作成してクライアントごとにすべてのマッピングを複製する必要があるため、扱いにくくなります。 このアプローチは、本当に必要であれば可能であり、その方法は、次のような特定のマッピングされたクラスで各クライアントにアクセスすることです。

client1_foo = Client1Foo()

で、その場合、quot;エンティティ名"のレシピで作業することになります。 http://www.sqlalchemy.org/trac/wiki/UsageRecipes/EntityName と連携して sometable.tometadata() (参照 http://docs.sqlalchemy.org/en/latest/core/metadata.html#sqlalchemy.schema.Table.tometadata ).

では、実際に動作する方法は、アプリ内で複数のクライアントを使用し、スレッドごとに一度に1つだけ使用することだとします。 実際、Postgresqlでそれを行う最も簡単な方法は、接続で作業を開始するときに検索パスを設定することでしょう。

# start request

# new session
sess = Session()

# set the search path
sess.execute("SET search_path TO client1")

# do stuff with session

# close it.  if you're using connection pooling, the
# search path is still set up there, so you might want to 
# revert it first
sess.close()

最後のアプローチは、@compiles 拡張を使用してコンパイラをオーバーライドし、ステートメント内で "schema" 名を固めることでしょう。 これは可能ですが、"Table"が生成される場所には一貫したフックがないため、厄介なことになります。 最善の策は、おそらく各リクエストで検索パスを設定することです。