如何使用 FastAPI 在 OpenAPI/Swagger 中记录默认 None/null?

Ziu*_*lpa 5 python database swagger openapi fastapi

使用 ORM,我想要执行一个 POST 请求,让某些字段具有null值,该值将在数据库中转换为那里指定的默认值。

问题是 OpenAPI (Swagger) docs忽略了默认值None,并且默认情况下仍然提示 a UUID

from fastapi import FastAPI
from pydantic import BaseModel
from typing import Optional
from uuid import UUID
import uvicorn


class Table(BaseModel):
    # ID: Optional[UUID]      # the docs show a example UUID, ok
    ID: Optional[UUID] = None # the docs still shows a uuid, when it should show a null or valid None value.

app = FastAPI()  
    
@app.post("/table/", response_model=Table)
def create_table(table: Table):
    # here we call to sqlalchey orm etc.
    return 'nothing important, the important thing is in the docs'
    
if __name__ == "__main__":
    uvicorn.run(app, host="0.0.0.0", port=8000)
Run Code Online (Sandbox Code Playgroud)

在文档中的 OpenAPI 架构示例(请求正文)中,我们发现:

{
 "ID": "3fa85f64-5717-4562-b3fc-2c963f66afa6"
}
Run Code Online (Sandbox Code Playgroud)

这是不行的,因为我指定了默认值None,所以我期望这样:

{
 "ID": null, # null is the equivalent of None here
}
Run Code Online (Sandbox Code Playgroud)

它将传递 anullID最后将在数据库中解析为默认值(即新生成的UUID)。

Chr*_*ris 8

当您声明Optional参数时,用户不应null在使用或(在 Python 中)指定的请求中包含这些参数None,以便None. 默认情况下,此类参数的值为None,除非用户在发送请求时指定其他值。

因此,您所要做的就是使用和声明examplePydantic 模型的自定义,如文档中所述并如下所示。下面的示例将在 OpenAPI (Swagger UI) 中创建一个空的(即 )请求正文,该请求正文可以成功提交(这是模型的唯一属性,并且是可选的)。Configschema_extra{}ID

class Table(BaseModel):
    ID: Optional[UUID] = None
    
    class Config:
        schema_extra = {
            "example": {
            }
        }

@app.post("/table/", response_model=Table)
def create_table(table: Table):
    return table
Run Code Online (Sandbox Code Playgroud)

如果Table模型包含一些其他必需的属性,您可以example为这些属性添加值,如下所示:

class Table(BaseModel):
    ID: Optional[UUID] = None
    some_attr: str
    
    class Config:
        schema_extra = {
            "example": {
                "some_attr": "Foo"
            }
        }
Run Code Online (Sandbox Code Playgroud)

如果您想保留除attribute之外的其余属性的自动生成示例,您可以使用以下命令从生成的架构中的模型属性中删除(受架构自定义的启发):IDID

class Table(BaseModel):
    ID: Optional[UUID] = None
    some_attr: str
    some_attr2: float
    some_attr3: bool
    
    class Config:
        @staticmethod
        def schema_extra(schema: Dict[str, Any], model: Type['Table']) -> None:
            del schema.get('properties')['ID']
Run Code Online (Sandbox Code Playgroud)

另外,如果您想example向某些属性添加自定义,您可以使用Field()(如此处所述;例如,some_attr: str = Field(example="Foo")

另一种可能的解决方案是修改生成的 OpenAPI 架构,如本答案的解决方案 3 中所述的解决方案 3 中所述。不过,上述解决方案可能更适合这种情况。

笔记

ID: Optional[UUID] = None是相同的ID: UUID = None。正如 FastAPI 网站先前记录的那样(请参阅此答案):

Optional[str]FastAPI 不使用Optional ,但它可以让您的编辑器为您提供更好的支持并检测错误。

从那时起,FastAPI 修改了其文档,内容如下:

联盟Union[str, None]将使您的编辑能够为您提供更好的支持并检测错误。

因此,ID: Union[UUID, None] = None相同。在Python 3.10+中,也可以使用(请参阅此处)。ID: Optional[UUID] = NoneID: UUID = NoneID: UUID| None = None

根据FastAPI 文档(请参阅Info提供的链接中的部分):

请记住,使参数可选的最重要部分 是:

= None
Run Code Online (Sandbox Code Playgroud)

或者:

= Query(default=None)
Run Code Online (Sandbox Code Playgroud)

因为它将使用它None作为默认值,这样就不需要该参数了。

Union[str, None]部分允许您的编辑器提供更好的支持,但这并不是告诉 FastAPI 不需要此参数。