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)
我应该使用每个请求的用户信息生成一个新的数据库会话吗?或者,还有更好的方法?
谢谢
这在 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)
| 归档时间: |
|
| 查看次数: |
1192 次 |
| 最近记录: |