Как обрабатывать создание схемы / таблиц «на лету» для многопользовательского веб-приложения

#postgresql #flask #sqlalchemy #flask-sqlalchemy #multi-tenant

#postgresql #flask #sqlalchemy #flask-sqlalchemy #многопользовательский

Вопрос:

Проблема

Я создаю веб-приложение, в котором каждый пользователь должен иметь отдельные данные (из-за конфиденциальности), но с точно такими же структурами данных / таблицами.

Оглядываясь вокруг, я думаю, что эта концепция называется многопользовательской? И кажется, что хорошим решением является 1 схема для каждого клиента.

Я думаю, что sqlalchemy 1.1 реализовал некоторую поддержку для этого с

 session.connection(execution_options={
    "schema_translate_map": {"per_user": "account_one"}})
  

Однако, похоже, предполагается, что схема и таблицы уже созданы.

Я не уверен, сколько клиентов у меня будет, поэтому мне нужно создать схему и таблицы внутри них «на лету», когда создается учетная запись пользователя.

Решение

То, что я придумал, похоже на небольшой взлом, поэтому я публикую здесь, чтобы узнать, есть ли лучшее решение.

Для создания схем «на лету» я использую

 if not engine.dialect.has_schema(engine, user.name):
   engine.execute(sqlalchemy.schema.CreateSchema(user.name))
  

А затем сразу после этого я создаю таблицы, используя

 table = TableModel()
table.__table__.schema = user.name
table.__table__.create(db.session.bind)
  

С помощью TableModel, определенной как

 class TableModel(Base):

    __tablename__ = 'users'

    __table_args__ = {'schema': 'public'}

    id = db.Column(
        db.Integer,
        primary_key=True
    )

    ...
  

Я не слишком уверен, зачем наследовать от Base vs db.Model — db.Model, похоже, автоматически создает общедоступную таблицу, чего я хочу избежать.

Бонусный вопрос

После создания схемы, если в дальнейшем мне нужно добавить таблицы ко всей схеме — каков наилучший способ управления этим? Справляется ли flask-migrations с этим изначально?

Спасибо!

Комментарии:

1. На данный момент у меня аналогичная проблема, я не такой продвинутый, как вы, но вы можете найти эти две ссылки полезными. В первой статье описывается подход, который, похоже, совпадает с вашим. medium.com/@hamza.senhajirhazi / … / Вторая статья является возможным ответом на ваш бонусный вопрос и касается автоматических миграций в Postgres, здесь на нескольких БД вместо схем: benchling.engineering/ …

2. Я не думаю, что в этой статье medium описывается, как создавать таблицы динамически, они создают таблицы с помощью редактора sql, хотя я не знал о before_request, который, похоже, будет полезен. Спасибо!

3. Вопрос… Использование разных схем полезно в модели арендатора с дифференцированными функциями для разных арендаторов. Если вы говорите, что данные будут точно такими же, почему бы вместо этого не использовать RLS? Это гораздо более простой процесс концептуально и оперативно.

4. @grommit Честно говоря, я не знал о RLS — я изучу это. Просто кажется, что наличие материала в одной таблице делает его менее безопасным? Но я думаю, это не обязательно верно, если оно реализовано правильно.

Ответ №1:

Если кто-нибудь увидит это в будущем, это решение, похоже, в целом работает, однако недавно я столкнулся с проблемой.

Эта строка

 table.__table__.schema = user.name
  

кажется, создает какое-то странное поведение, когда значение user.name кажется, сохраняется в областях заказа приложения, поэтому, если вы переключаете пользователя, таблица от предыдущего пользователя запрашивается неправильно.

Я не совсем уверен, почему это происходит, и все еще изучаю, как это исправить.