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

Arn*_*rne 10 python pydantic fastapi

我想将自定义类包含到路线的响应中。我主要pydantic.BaseModel在应用程序中使用嵌套,因此最好返回整个内容,而无需编写从内部数据表示到路由返回内容的翻译。

只要继承自此的所有内容pydantic.BaseModel都是微不足道的,但我在后端使用的类Foo无法做到这一点,而且我也无法为此目的对其进行子类化。我可以以某种方式fastapi以接受该类的定义的方式鸭子类型吗?我现在所拥有的基本上是这样的:

主要.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
Run Code Online (Sandbox Code Playgroud)

Arn*_*rne 9

它没有记录,但您可以使非pydantic类与fastapi. 你需要做的是:

  1. 告诉pydantic我们使用任意类都可以。它将尝试使用 jsonify 它们vars(),因此只有直接的数据容器才能工作 - 不使用 usingproperty__slots__类似的东西[1]

  2. 创建一个代理BaseModel,并告诉Foo在有人询问其架构时提供它 - 这就是fastapiOpenAPI 页面所做的。我只是假设你也希望它们能够工作,因为它们太棒了。

主要.py

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
Run Code Online (Sandbox Code Playgroud)

[1]如果您想要更复杂的 jsonification,您需要Response通过 显式地将其提供给类Config.json_encoders