Multi-tenancy with SQLAlchemy

后端 未结 3 408
被撕碎了的回忆
被撕碎了的回忆 2020-12-28 09:36

I\'ve got a web-application which is built with Pyramid/SQLAlchemy/Postgresql and allows users to manage some data, and that data is almost completely independent for differ

3条回答
  •  野趣味
    野趣味 (楼主)
    2020-12-28 10:06

    What works very well for me it to set the search path at the connection pool level, rather than in the session. This example uses Flask and its thread local proxies to pass the schema name so you'll have to change schema = current_schema._get_current_object() and the try block around it.

    from sqlalchemy.interfaces import PoolListener
    class SearchPathSetter(PoolListener):
        '''
        Dynamically sets the search path on connections checked out from a pool.
        '''
        def __init__(self, search_path_tail='shared, public'):
            self.search_path_tail = search_path_tail
    
        @staticmethod
        def quote_schema(dialect, schema):
            return dialect.identifier_preparer.quote_schema(schema, False)
    
        def checkout(self, dbapi_con, con_record, con_proxy):
            try:
                schema = current_schema._get_current_object()
            except RuntimeError:
                search_path = self.search_path_tail
            else:
                if schema:
                    search_path = self.quote_schema(con_proxy._pool._dialect, schema) + ', ' + self.search_path_tail
                else:
                    search_path = self.search_path_tail
            cursor = dbapi_con.cursor()
            cursor.execute("SET search_path TO %s;" % search_path)
            dbapi_con.commit()
            cursor.close()
    

    At engine creation time:

    engine = create_engine(dsn, listeners=[SearchPathSetter()])
    

提交回复
热议问题