设计模式来组织非平凡的ORM查询?

时间:2010-02-15 10:24:05

标签: python design-patterns orm refactoring sqlalchemy

我正在开发一个在后端有10个左右的表格的Web API,有几个一对多和多对多的关联。 API本质上是一个执行验证更新和条件查询的数据库包装器。它是用Python编写的,我使用SQLAlchemy进行ORM,使用CherryPy进行HTTP处理。

到目前为止,我已将API执行的30个查询分离为自己的函数,如下所示:

# in module "services.inventory"
def find_inventories(session, user_id, *inventory_ids, **kwargs):
    query = session.query(Inventory, Product)
    query = query.filter_by(user_id=user_id, deleted=False)
    ...
    return query.all()

def find_inventories_by(session, app_id, user_id, by_app_id, by_type, limit, page):
    ....

# in another service module
def remove_old_goodie(session, app_id, user_id):
    try:
        old = _current_goodie(session, app_id, user_id)
        services.inventory._remove(session, app_id, user_id, [old.id])
    except ServiceException, e:
        # log it and do stuff
....

CherryPy请求处理程序根据需要调用分散在多个服务模块中的查询方法。这个解决方案背后的基本原理是,由于它们需要访问多个模型类,因此它们不属于单个模型,并且这些数据库查询也应该与API访问的直接处理分开。

我意识到上面的代码可能在重构领域被称为Foreign Methods。我可以用这种组织方式生活一段时间,但随着事情开始变得有些混乱,我正在寻找一种方法来重构这段代码。

  • 由于查询直接与API及其业务逻辑相关联,因此很难像getter和setter那样概括。
  • 它有点像这样重复session参数,但是因为API的当前实现为每个API调用创建一个新的CherryPy处理程序实例,因此session对象,没有全局方式获得当前session

是否有完善的模式来组织此类查询?我应该坚持使用外来方法,并尝试统一函数签名(参数排序,命名约定等)?你会建议什么?

2 个答案:

答案 0 :(得分:1)

SQLAlchemy强烈建议会话制作者参与某些全局配置。

  

这是sessionmaker()的意图   函数在全局范围内调用   申请范围和   返回课程可供使用   其余的应用程序作为   用于实例化的单个类   会话。

在单独模块中的查询不是一个有趣的问题。 Django ORM以这种方式工作。一个网站通常由多个Django“应用程序”组成,这听起来像您的网站有许多“服务模块”。

将多个服务编织在一起是应用程序的重点。没有很多替代方案更好。

答案 1 :(得分:1)

在线程环境中对当前会话进行全局访问的标准方法是ScopedSession。在与框架集成时,有一些重要方面可以正确实现,主要是事务控制和清除请求之间的会话。一个常见的模式是在模块中有一个autocommit = False(默认值)ScopedSession,并将任何业务逻辑执行包装在try-catch子句中,该子句在异常情况下回退并在方法成功时提交,然后最终调用Session.remove ()。然后,业务逻辑将Session对象导入全局范围,并像常规会话一样使用它。

似乎存在CherryPy-SQLAlchemy integration module,但由于我对CherryPy不太熟悉,我无法对其质量发表评论。

将查询封装为函数就可以了。并非一切都需要在课堂上。如果它们太多而只是按主题分成单独的模块。

我发现有用的东西也是常见的标准片段。它们通常适合作为模型类的类方法。除了提高可读性和减少重复之外,它们还可以作为实现在某种程度上隐藏抽象,使重构数据库变得不那么痛苦。 (示例:代替(Foo.valid_from <= func.current_timestamp()) & (Foo.valid_until > func.current_timestamp())您有Foo.is_valid()