Примените глобальный фильтр ко всем таблицам для каждого запроса в SQLAlchemy

#sqlalchemy

#sqlalchemy

Вопрос:

Мы пытаемся настроить службу SaaS, которая поддерживает многопользовательскую работу в общей базе данных и схеме. Мы планируем иметь столбец tenant_id во всех наших таблицах. что я хотел бы сделать, так это то, что разработчику не нужно писать какой-либо дополнительный код, чтобы мои запросы автоматически фильтровали все задействованные таблицы по этому идентификатору клиента. Есть ли прозрачный способ добиться этого в SQL Alchemy?

Я нашел, как вы можете переопределить объект запроса по умолчанию:

 self.session = sessionmaker(bind=engine, query_cls=TenantLimitingQuery)
  

Но внутри этого TenantLimitingQuery как можно применить его ко всем задействованным таблицам?

 class TenantLimitingQuery(Query):
    def get(self, ident):
        #apply filter here
  

В моих таблицах есть один и тот же столбец для идентификации арендатора с именем tenant_id, поэтому в этой функции get мне нужно выполнить фильтрацию по tenant_id=current_tenant_id

Ответ №1:

Это изложено в вики-рецептах использования, воспроизведенных здесь:

 from sqlalchemy.orm.query import Query

class LimitingQuery(Query):

    def get(self, ident):
        # override get() so that the flag is always checked in the 
        # DB as opposed to pulling from the identity map. - this is optional.
        return Query.get(self.populate_existing(), ident)

    def __iter__(self):
        return Query.__iter__(self.private())

    def from_self(self, *ent):
        # override from_self() to automatically apply
        # the criterion too.   this works with count() and
        # others.
        return Query.from_self(self.private(), *ent)

    def private(self):
        mzero = self._mapper_zero()
        if mzero is not None:
            crit = mzero.class_.public == True

            return self.enable_assertions(False).filter(crit)
        else:
            return self
  

Идея состоит в том, чтобы применять фильтр по требованию, когда объект запроса повторяется.

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

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

1. Эту суть можно использовать для фильтров по умолчанию, специфичных для конкретной модели gist.github.com/aklos/6c4afd656d1c8fdf1dad