4

我打算使用 Flask 和 MongoDB(可能还有 Ming 作为 ODM)在 python 中编写一个 webapp。问题是我想让我的模型和控制器很好地分开,这样做的一个原因是能够在单独的组件上运行简单的单元测试。

现在这是我的问题,在请求生命周期的某个时刻,我需要连接到 MongoDB。每个请求都有一个单独的连接。Flask 提供了一个线程本地对象,它可以包含任何对请求全局的变量,这似乎是放置 mongo 连接的好地方。但是,这会在数据层和 Flask 之间产生硬依赖,这将使单独测试或运行它们变得非常困难。

所以我的问题真的是是否有一个优雅的解决方案。我自己提出了几个选项,但它们远非优雅。

首先,我可以给数据模块一个函数,告诉它从哪里获取连接对象。或者类似地给它一个可以用来获取新连接的函数。

第二种选择是创建一个模块可以用来连接到 MongoDB 的类,然后创建这个类的 2 个版本,一个使用 Flask 的全局对象,另一个只是简单地连接到 MongoDB。

这两个对我来说似乎都不是很健壮或优雅,有没有办法更好地做到这一点?

4

1 回答 1

5

一种方法是利用 Python 模块级单例模式。创建一个具有“conn”对象的模块,(仅使用普通 PyMongo)

try:
    conn = Connection(max_pool_size=20)
except ConnectionFailure:
    app.logger.critical("Unable to connect to MongoDB")

然后为 PyMongo 集合创建一个包装器

class Model(object):
    def __init__(self, table, db = app.config['DB_NAME']):
        self._table = table
        self._db = db

    def find_one(self, spec_or_id=None, *args, **kwargs):
        result = None
        try:
            result = conn[self._db][self._table].find_one(spec_or_id, *args, **kwargs)
        except InvalidName:
            app.logger.critical('invalid DB or Table name')
        finally:
            conn.end_request()

        return result

conn.end_request()将导致连接返回到池中,并且在每个 find_one() 上它将从池中获取连接。别担心,它们是线程安全的。

现在你可以使用类似的模型

result = Model(COLLECTION).find_one({user:'joe'})
于 2011-12-17T14:57:18.037 回答