对SQLAlchemy中的每个查询的所有表应用全局过滤器

时间:2016-10-04 12:28:57

标签: sqlalchemy

我们正在尝试在共享数据库和架构中设置支持多租户的SaaS服务。我们计划在所有表格上都有一个tenant_id列。我想做的是,没有开发人员必须编写任何额外的代码,我的查询将通过此租户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 个答案:

答案 0 :(得分:1)

这在usage recipes wiki中概述,转载于此处:

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

我们的想法是在迭代查询对象时按需应用过滤器。

如果您希望过滤器也适用于关系,则需要使用this recipe代替。