У меня есть приложение, запущенное в производство, которое я создал для одного клиента, которое я хочу преобразовать для поддержки нескольких «арендаторов».
В настоящее время я использую базу данных Postgres, где все мои данные хранятся в одной базе данных в схеме public
по умолчанию. Я хотел бы изолировать каждого арендатора в отдельной схеме Postgres. В идеале пользовательский интерфейс моего приложения должен вызывать мой 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;")