如何使用 Python Pyramid 处理多个数据库

Dav*_*vid 3 python database sqlalchemy pyramid

我想使用 Python Pyramid Framework 和 SQL Alchemy 处理多个数据库。

我有 1 个包含用户信息的数据库,以及多个存储应用程序信息的数据库(具有相同的结构)。每个用户在登录时选择一个数据库,并且只显示来自该数据库(而不是其他数据库)的信息。

我应该如何构建我的代码?

我正在考虑在会话中保存 dbname 并在每个请求中检查所选数据库的用户权限并生成一个新的 db 会话。所以我的观点看起来像(伪代码):

@view_config(route_name='home', renderer='json')

def my_view_ajax(request):

    try:

        database = int(request.GET['database'])

        # check user permissions from user database

        engine = create_engine('postgresql://XXX:XXX@localhost/'+database)

        DBSession.configure(bind=engine)

        items = DBSession.query('table').all()

    except DBAPIError:

        return 'error'

    return items
Run Code Online (Sandbox Code Playgroud)

我应该使用每个请求的用户信息生成一个新的数据库会话吗?或者,还有更好的方法?

谢谢

Iai*_*can 5

这在 Pyramid+SQLAlchemy 中很容易做到,但是您可能希望切换到更重的样板文件、更手动的会话管理样式,并且您将希望查看 SQLA 的会话管理文档,因为您可以轻松地在处理多个并发会话时绊倒。此外,诸如连接管理之类的东西应该远离视图,并位于服务器启动生命周期中的组件中,并在请求线程之间共享。如果您在 Pyramid 中做得对,那么您的视图应该非常小,并且您应该有很多组件通过 ZCA(注册表)协同工作。

在我的应用程序中,我有一个 db factory 对象,可以在需要时获取会话,并且我在服务器启动代码(__ init __.py 中的内容)中实例化这些对象并将它们保存在注册表中。然后,您可以使用 reify 装饰器将每个数据库的会话附加到您的请求对象,并附加一个内务处理结束请求清理方法来关闭它们。这可以通过自定义请求工厂或直接从 init 附加到请求的方法来完成,我个人最终使用自定义工厂,因为我发现它更容易阅读,而且我通常最终会在那里添加更多内容。

# our DBFactory component, from some model package
class DBFactory(object):

    def __init__(self, db_url, **kwargs):
        db_echo = kwargs.get('db_echo', False)
        self.engine = create_engine(db_url, echo=db_echo)

        self.DBSession = sessionmaker(autoflush=False)
        self.DBSession.configure(bind=self.engine)
        self.metadata = Base.metadata
        self.metadata.bind = self.engine

    def get_session(self):
        session = self.DBSession()
        return session


# we instantiate them in the __init__.py file, and save on registry
def main(global_config, **settings):
    """runs on server start, returns a Pyramid WSGI application  """

    config = Configurator(
        settings=settings,
        # ask for a custom request factory
        request_factory = MyRequest,
    )

    config.registry.db1_factory = DBFactory( db_url=settings['db_1_url'] )
    config.registry.db2_factory = DBFactory( db_url=settings['db_2_url'] )


# and our custom request class, probably in another file
class MyRequest(Request):
    "override the pyramid request object to add explicit db session handling"

    @reify
    def db1_session(self):
        "returns the db_session at start of request lifecycle"
        # register callback to close the session automatically after
        # everything else in request lifecycle is done
        self.add_finished_callback( self.close_dbs_1 )
        return self.registry.db1_factory.get_session()

    @reify
    def db2_session(self):
        self.add_finished_callback( self.close_dbs_2 )
        return self.registry.db2_factory.get_session()

    def close_dbs_1(self, request):
        request.db1_session.close()

    def close_dbs_2(self, request):
        request.db2_session.close()


# now view code can be very simple    
def my_view(request):
    # get from db 1
    stuff = request.db1_session.query(Stuff).all()
    other_stuff = request.db2_session.query(OtherStuff).all()
    # the above sessions will be closed at end of request when 
    # pyramid calls your close methods on the Request Factory

    return Response("all done, no need to manually close sessions here!")
Run Code Online (Sandbox Code Playgroud)