首页 > 解决方案 > PonyORM/Postgres 多租户选项

问题描述

我有一个在生产中运行的应用程序,它是为单个客户端构建的,我想将其转换为支持多个“租户”。

目前我正在使用 Postgres 数据库,其中我的所有数据都驻留在默认public模式中的单个数据库中。我想将每个租户隔离到一个单独的 Postgres 模式。理想情况下,我的应用程序 UI 会使用租户的子域调用我的 API。在before_request我将能够以某种方式在当前请求上下文期间设置所有数据库查询以仅查询该租户的架构,这可能吗?

我设想一个理想的解决方案类似于这个人为的例子:

from flask import Flask, request, jsonify
from pony.orm import Database, Required

app = Flask(__name__)
db = Database(**{<db_connection_dict>})

class User(db.Entity):
  email = Required(str)
  password = Required(str)

  @classmethod
  def login(cls, email: str, password: str) -> str:
    user = cls.get(lambda u: u.email.lower() == email.lower())
    if not user:
      return None
    password_is_valid = <method_to_check_hashed_pasword>
    if not password_is_valid:
      return None
    return <method_to_generate_jwt>

db.generate_mapping()

@app.before_request
def set_tenant():
  tenant_subdomain = request.host.split(".")[0]
  // MISSING STEP.. set_schema is a fictitous method, does something similar to this exist?
  db.set_schema(schema=tenant_subdomain)??

@app.route("auth/login", methods=["POST"]
def login_route():
  data = request.get_json()
  jwt = User.login(data["email"], data["password"])
  if not jwt:
   return make_response({}, 403)
  return make_response(jsonify(data=jwt), 200)

我遇到了一个使用 SQLAlchemy的有趣/简单的示例。如果无法使用 PonyORM,我可能会考虑将我的模型移植到 SQLAlchemy,但会错过 Pony 的简单性:(

我考虑过可能使用这种Database.on_connect方法来做这样的事情,但不确定是否有人有任何其他想法,或者这是否会在生产中正常工作。我怀疑不是因为如果我有两个单独的租户查询数据库,他们会覆盖搜索路径..

@db.on_connect()
def set_request_context_tenant_schema(db, connection) -> None:
    subdomain = request.host.split(".")[0]
    cursor = connection.cursor()
    cursor.execute(f"SET search_path TO {subdomain}, public;")

标签: pythonpostgresqlflaskmulti-tenantponyorm

解决方案


推荐阅读