MongoDb 使用 FastAPI

MongoDb with FastAPI

我正在玩 FastAPI a bit and wanted to connect it to a MongoDB database. I however am confused which ODM to choose between motor which is async and mongoengine. Also, in the NoSQL example here 他们已经创建了一个新的存储桶,并且还调用了每次使用时连接到数据库的代码。但是,motor 和 mongoengine 似乎都更喜欢全局连接。那么连接到 mongodb 的好方法是什么?

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

简而言之,您可以使用任何一种 motor or mongoengine,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 with FastAPI,async 应该 "just work"。不幸的是,Motor 没有实施 ODM。在这个意义上它更类似于pymongo。

Fastapi 处理来自客户端的请求(使用 Starlette),但它会让您实现自己与 MongoDB 的连接。所以你不局限于任何特定的选择,但你主要是靠自己(一个 la Flask)。

您可以使用 FastAPI 应用程序的 startup/shutdown 挂钩到 start/stop 您的 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

可以找到使用 Fastapi 实现电机的示例 here

我最近创建了一个非常适合 FastAPI 的异步 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

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