如何在 fastapi 响应中包含非 pydantic 类?

How to include non-pydantic classes in fastapi responses?

我想在路由的响应中包含自定义 class。我主要在我的应用程序中使用嵌套的 pydantic.BaseModels,所以最好 return 整个事情而不用编写从内部数据表示到路由 returns 的翻译。

只要 一切 继承自 pydantic.BaseModel 这是微不足道的,但我在后端使用 class 无法做到这一点.我能否以某种方式以 fastapi 接受的方式隐藏 class 的定义?我现在拥有的基本上是这样的:

main.py

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Foo:
    """Foo holds data and can't inherit from `pydantic.BaseModel`."""
    def __init__(self, x: int):
        self.x = x


class Response(BaseModel):
    foo: Foo
    # plus some more stuff that doesn't matter right now because it works


@app.get("/", response_model=Response)
def root():
    return Response(foo=Foo(1))


if __name__ == '__main__':
    import uvicorn
    uvicorn.run("main:app")  # RuntimeError

它没有记录,但您可以使非 pydantic class 与 fastapi 一起工作。您需要做的是:

  1. 告诉 pydantic 使用任意 classes 是可以的。它 将尝试使用 vars() 对它们进行 jsonify,所以只需要直接 数据容器可以工作——不要使用 property__slots__ 或类似的东西 [1].

  2. 创建一个代理 BaseModel,并告诉 Foo 如果有人提供它 询问它的模式——这就是 fastapis OpenAPI 页面所做的。 我只是假设你希望他们也工作,因为他们是 厉害了。

from fastapi import FastAPI
from pydantic import BaseModel, BaseConfig, create_model

app = FastAPI()
BaseConfig.arbitrary_types_allowed = True  # change #1


class Foo:
    """Foo holds data and can't inherit from `pydantic.BaseModel`."""    
    def __init__(self, x: int):
        self.x = x

    __pydantic_model__ = create_model("Foo", x=(int, ...))  # change #2


class Response(BaseModel):
    foo: Foo


@app.get("/", response_model=Response)
def root():
    return Response(foo=Foo(1))


if __name__ == '__main__':
    import uvicorn
    uvicorn.run("main:app")  # works

[1] 如果你想要更复杂的 jsonification,你需要通过 Config.json_encoders 显式地提供给 Response class。