如果想使用 SQLAlchemy 将多个数据库连接到各种应用程序,组织模型和连接的好方法是什么?
What is a good way to organize your models, connections if one wants to use SQLAlchemy to connect several databases to various applications?
背景:
这就是我面临的情况,到目前为止,我目前的解决方案似乎相当笨拙。我想改进它。现在:
- 我在 Pyramid 应用程序的主要功能中设置了与每个数据库的连接:
def main(global_config, **settings):
a_engine = engine_from_config(settings, 'A.')
b_engine = engine_from_config(settings, 'B.')
ASession.configure(bind=a_engine)
BSession.configure(bind=b_engine)
- "ASession" 和 "BSession" 只是全局定义 scoped_session 在 /models/init.py.
ASession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
- 我这样定义模型基础class。例如:
ABase = declarative_base()
class user(ABase):
id = Column(Integer, primary_key=True)
name = Column(String)
这不知何故已经感觉不太干净了。但现在这个模型应该从不同的应用程序访问,我还需要在该应用程序中再次定义引擎和连接。这感觉非常多余。
抽象问题:
假设有2个不同的数据库:
A 和 B
还假设您希望使用相同模型的 2 个不同应用程序(例如:Pyramid 应用程序、使用 Tornado 的 Bokeh 服务器应用程序)可以访问 A 和 B。
简而言之,一种最佳模式 objects/models/classes/functions 如何在 Python3 中生成干净的非冗余代码?
问题发布后的初步想法:
再考虑一下,我想我希望每个模型都以某种方式“独立”。该模型应带有启动连接的方法。换句话说,数据库连接的发起应该与Web应用程序本身解耦。
并且应该以实例的方式完成。这样多个应用程序就可以使用相同的模型。每个应用程序都会有自己的会话连接到任一数据库。
社区将如何设计?至少周五下午不适合自己去寻找这类问题的答案。
我已经做到了。我在下面的建议是我喜欢这样做的方式,但不是唯一的方式。我会放弃作用域会话和事务管理器,并创建明确的会话管理对象,请求生命周期回调处理创建、关闭、提交或回滚会话。基本上,作用域会话是一种通过为该执行线程获取相同项目来模拟全局的方法。在 Pyramid 中执行此操作的另一种方法是将内容附加到注册表和请求,因为你 无处不在 。您将共享组件附加到注册表(ZCA)并将每个请求对象附加到请求。
当您有多个会话时,我发现如果它们由包含该引擎所有内容的组件处理,则更容易推理和跟踪它们。因此,对于您描述的这种情况,我制作了两个不同的数据库引擎组件,它们在启动时创建,附加到注册表,并且有一个获取新会话的方法。如果您正确地创建了这些组件,它们应该可以在任何应用程序中使用,无论是 Pyramid、Tornado 还是您的测试脚本。您只需确保它有一个构造函数,该构造函数可以通过某种理智的方式传递设置引擎的设置,无论它是设置字典还是 kwargs。然后我让我的数据模型存在于它们自己的 python 包中,并且很容易让系列中的任何应用程序导入模型,实例化引擎组件并进入城镇。请注意,如果您喜欢使用 ZCA 注册表(我喜欢它,它是一个很棒的 DI 系统),没有什么可以阻止您在非金字塔应用程序中使用它,您只需在服务器启动代码中手动设置它。
特别是在 Pyramid 中,我创建了一个自定义请求 class 并使用 reify 装饰器允许其他金字塔代码获取该请求的会话。请求 class 附加了生命周期结束回调以关闭会话,并进行回滚或提交。有更多的样板文件,但对我来说它更清晰,因为我可以很容易地跟踪我的会话管理发生在代码和时间中的位置和时间。这也是测试的好方法。
就是说,在 SQLAlchemy/Pyramid 地区有很多聪明人对作用域会话和事务管理器发誓,所以还有其他有效的方法。希望对您有所帮助。
背景:
这就是我面临的情况,到目前为止,我目前的解决方案似乎相当笨拙。我想改进它。现在:
- 我在 Pyramid 应用程序的主要功能中设置了与每个数据库的连接:
def main(global_config, **settings): a_engine = engine_from_config(settings, 'A.') b_engine = engine_from_config(settings, 'B.') ASession.configure(bind=a_engine) BSession.configure(bind=b_engine)
- "ASession" 和 "BSession" 只是全局定义 scoped_session 在 /models/init.py.
ASession = scoped_session(sessionmaker(extension=ZopeTransactionExtension()))
- 我这样定义模型基础class。例如:
ABase = declarative_base() class user(ABase): id = Column(Integer, primary_key=True) name = Column(String)
这不知何故已经感觉不太干净了。但现在这个模型应该从不同的应用程序访问,我还需要在该应用程序中再次定义引擎和连接。这感觉非常多余。
抽象问题:
假设有2个不同的数据库:
A 和 B
还假设您希望使用相同模型的 2 个不同应用程序(例如:Pyramid 应用程序、使用 Tornado 的 Bokeh 服务器应用程序)可以访问 A 和 B。
简而言之,一种最佳模式 objects/models/classes/functions 如何在 Python3 中生成干净的非冗余代码?
问题发布后的初步想法:
再考虑一下,我想我希望每个模型都以某种方式“独立”。该模型应带有启动连接的方法。换句话说,数据库连接的发起应该与Web应用程序本身解耦。
并且应该以实例的方式完成。这样多个应用程序就可以使用相同的模型。每个应用程序都会有自己的会话连接到任一数据库。
社区将如何设计?至少周五下午不适合自己去寻找这类问题的答案。
我已经做到了。我在下面的建议是我喜欢这样做的方式,但不是唯一的方式。我会放弃作用域会话和事务管理器,并创建明确的会话管理对象,请求生命周期回调处理创建、关闭、提交或回滚会话。基本上,作用域会话是一种通过为该执行线程获取相同项目来模拟全局的方法。在 Pyramid 中执行此操作的另一种方法是将内容附加到注册表和请求,因为你 无处不在 。您将共享组件附加到注册表(ZCA)并将每个请求对象附加到请求。
当您有多个会话时,我发现如果它们由包含该引擎所有内容的组件处理,则更容易推理和跟踪它们。因此,对于您描述的这种情况,我制作了两个不同的数据库引擎组件,它们在启动时创建,附加到注册表,并且有一个获取新会话的方法。如果您正确地创建了这些组件,它们应该可以在任何应用程序中使用,无论是 Pyramid、Tornado 还是您的测试脚本。您只需确保它有一个构造函数,该构造函数可以通过某种理智的方式传递设置引擎的设置,无论它是设置字典还是 kwargs。然后我让我的数据模型存在于它们自己的 python 包中,并且很容易让系列中的任何应用程序导入模型,实例化引擎组件并进入城镇。请注意,如果您喜欢使用 ZCA 注册表(我喜欢它,它是一个很棒的 DI 系统),没有什么可以阻止您在非金字塔应用程序中使用它,您只需在服务器启动代码中手动设置它。
特别是在 Pyramid 中,我创建了一个自定义请求 class 并使用 reify 装饰器允许其他金字塔代码获取该请求的会话。请求 class 附加了生命周期结束回调以关闭会话,并进行回滚或提交。有更多的样板文件,但对我来说它更清晰,因为我可以很容易地跟踪我的会话管理发生在代码和时间中的位置和时间。这也是测试的好方法。
就是说,在 SQLAlchemy/Pyramid 地区有很多聪明人对作用域会话和事务管理器发誓,所以还有其他有效的方法。希望对您有所帮助。