Я использую базу данных Postgres. Приложение Flask читает из базы данных. Задание префекта использует ту же базу кода и регулярно обновляет базу данных. /Отсутствие арендаторов в базе данных «Одна схема на арендатор» довольно сложно, мы решили пойти с общими таблицами (общие таблицы имеют столбец venant_id ).
Как мы может переехать в другую систему баз данных, мы не хотим использовать функцию RLS Postgres. Для этой настройки общего стола-мультленсии в Sqlalchemy?! Я нашел старую мультиальную библиотеку , но она была архивирована в 2022 году, а последний коммит был 9 лет назад: https://github.com/mwhite/multialchemy
Я начал Написание моего собственного множественного контекстного манагер (используя глобальные критерии ORM), но это довольно сложно сделать ... < /p>
Код: Выделить всё
class HasClientColumn(object):
"""Mixin that identifies a class as having a tenant/client column"""
client_id = Column(BigInteger, nullable=False)
class Testerle(HasClientColumn, Base):
__tablename__ = "testerle"
id = Column(BigInteger, primary_key=True, autoincrement=True)
secret = Column(Text)
class Testerle2(HasClientColumn, Base):
__tablename__ = "testerle2"
id = Column(BigInteger, primary_key=True, autoincrement=True)
secret = Column(Text)
db_sessionmaker = sessionmaker(
autocommit=False, autoflush=False, bind=db_engine, future=True
)
def get_client_scoped_db_session(client_id: int):
session = db_sessionmaker()
# Overwrite execute method so nobody uses it without ORM
session.execute = lambda x, *args, **kwargs: _raise(
Exception(
"client_scoped_db_session not meant to be used with execute command (unsafe). Use ORM!"
)
)
# Docs: https://docs.sqlalchemy.org/en/14/orm/session_events.html#do-orm-execute-global-criteria
@event.listens_for(session, "do_orm_execute")
def _do_orm_execute(orm_execute_state):
if (
orm_execute_state.is_select
and not orm_execute_state.is_column_load
and not orm_execute_state.is_relationship_load
):
orm_execute_state.statement = orm_execute_state.statement.options(
with_loader_criteria(
HasClientColumn,
lambda cls: cls.client_id == client_id,
include_aliases=True,
)
)
return session
@contextmanager
def with_client_scoped_db_session(client_id: int):
session = False
try:
logging.debug(f"Establishing DB session for client {client_id}")
session = get_client_scoped_db_session(client_id)
yield session
session.commit()
except Exception as e:
logging.exception(f"Exception in with_client_scoped_db({client_id}): {e}")
if session:
session.rollback()
raise e
finally:
logging.debug(f"Closing DB session for client {client_id}")
if session:
session.close()
< /code>
Это работает довольно хорошо, когда просто вызывает такие вещи, как < /p>
with with_client_scoped_db_session(1) as session:
session.query(Testerle).all()
< /code>
Но всякий раз, когда я делаю присоединение, как < /p>
with with_client_scoped_db_session(1) as session:
session.query(Testerle, Testerle2.secret).join(Testerle2, Testerle.id == Testerle2.id).all()
< /code>
он сталкивается с моим пользовательским исключением, говоря, что метод выполнения запрещен (client_scoped_db_session not meant to be used with execute command (unsafe). Use ORM!
Любые идеи, как реализовать стабильную и безопасную многопользовательство с общими таблицами, используя Sqlalchemy без постгресса RLS?
Подробнее здесь: https://stackoverflow.com/questions/794 ... ared-table