带有 FastAPI 的 MongoDb

Ayu*_*ngh 12 mongodb mongoengine tornado-motor motorengine fastapi

我正在使用FastAPI并希望将其连接到 MongoDB 数据库。然而,我很困惑在异步电机和 mongoengine 之间选择哪个 ODM。此外,在此处的 NoSQL 示例中他们创建了一个新存储桶,并在每次使用时调用了连接到 db 的代码。但是,motor 和 mongoengine 似乎都更喜欢全局连接。那么什么是连接到 mongodb 的好方法呢?

小智 27

我相信您已经在 Github 上 Fastapi 项目的问题论坛中得到了答案:Issue 452 (closed)。但我会在这里回顾一下解决方案以供将来参考:

简而言之,您可以使用motormongoengine,Fastapi 两者都支持,并且您可以重用在您的应用程序进程中启动和结束的全局客户端对象。

一些上下文细节(希望)阐明这些技术及其关系:

Python 的官方 MongoDB 驱动程序是pymongo。在引擎盖下,MongoEngine 和 Motor 都使用 Pymongo。Pymongo 为 MongoDB(守护进程)实现了一个直接客户端,并提供了一个 Python API 来发出请求。

如果您愿意,可以直接将 pymongo 与 Fastapi 一起使用。(在 SQL 方面,这相当于直接在 Flask 中使用 psycopg2 而无需通过 SQLAlchemy 之类的东西。)

MongoEngine 是一个 ODM(对象文档映射器)。它提供了一个 Python 面向对象的 API,你可以在你的应用程序中使用它来更舒适地工作,当涉及到实际的数据库请求时,MongoEngine 将使用 pymongo。

Motor 是 pymongo 的包装器,使其非阻塞(允许 async/await)。它使用事件循环,通过 Tornado 或通过 asyncio。如果您将 Fastapi 与 uvicorn 一起使用,则 uvicorn 将使用 uvloop 实现异步功能。简而言之,将 Motor 与 FastAPI 一起使用,异步应该“正常工作”。不幸的是,Motor 没有实施 ODM。从这个意义上说,它更类似于 pymongo。

Fastapi 处理来自客户端的请求(使用 Starlette),但它可以让您实现自己的 MongoDB 连接。因此,您不受任何特定选择的限制,但您主要依靠自己(a la Flask)。

您可以使用 FastAPI 应用程序的启动/关闭挂钩来启动/停止您的 Motor/MongoEngine 客户端。由于多进程问题,您无需担心客户端对象不会持久化,因为 Fastapi 是单线程的。

@app.on_event("startup")
async def create_db_client():
    # start client here and reuse in future requests


@app.on_event("shutdown")
async def shutdown_db_client():
    # stop your client here
Run Code Online (Sandbox Code Playgroud)

可以在此处找到带有 Fastapi 的电机的示例实现。


art*_*049 6

我最近创建了一个非常适合 FastAPI 的 Async Mongo ODM:ODMantic

app = FastAPI()
engine = AIOEngine()

class Tree(Model):
    """This model can be used either as a Pydantic model or 
       saved to the database"""
    name: str
    average_size: float
    discovery_year: int

@app.get("/trees/", response_model=List[Tree])
async def get_trees():
    trees = await engine.find(Tree)
    return trees

@app.put("/trees/", response_model=Tree)
async def create_tree(tree: Tree):
    await engine.save(tree)
    return tree
Run Code Online (Sandbox Code Playgroud)

您可以查看FastAPI 示例以获取更详细的示例。