以可测试的方式连接到 mongodb

发布于 2024-12-21 19:29:51 字数 529 浏览 0 评论 0原文

我计划使用 Flask 和 MongoDB(可能还有 Ming 作为 ODM)用 python 编写一个 web 应用程序。问题是我想让我的模型和控制器真正分开,原因之一是能够在单独的组件上运行简单的单元测试。

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

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

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

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

这两个对我来说似乎都不是很健壮或优雅,有什么办法可以做得更好吗?

I'm planning to write a webapp in python using Flask and MongoDB (and probably Ming as ODM). The problem is I would like to keep my model and controller really well separated, one reason for this would be to be able to run simple unittests on the separate components.

Now here is my problem, at some point in the request lifecycle I need to connect to MongoDB. Each request will have a separate connection. Flask offers a thread local object that can contain any variables that are global to the request, this seems to be a good place to put the mongo connection. However, this creates a hard dependency between the data layer and Flask, which will make testing or running them separately quite hard.

So my question really is whether or not there is an elegant solution for this. I've come up with a couple of options myself, but they are very far from elegant.

First I could just give the data module a function that would tell it where to get the connection object from. Or similarly hand it a function that it can use to fetch a new connection.

The second option is to create a class that the module can use to get a connection to MongoDB, and then create 2 versions of this class, one that uses Flask's global object, and the other just plainly connects to MongoDB.

Both of these don't seem really robust or elegant to me, is there any way to do this better?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

没企图 2024-12-28 19:29:51

一种方法是使用 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'})

One approach could be to make use of Python module level singleton pattern.
Create a module having 'conn' object, (using just plain PyMongo)

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

and then just create a wrapper for PyMongo collection

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

Here conn.end_request() will cause connection to return to the pool and on each find_one() it will get the connection from pool. Don't worry, they are thread safe.

now you can use the model something like

result = Model(COLLECTION).find_one({user:'joe'})
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文