gpt4 book ai didi

python - 为什么使用 FastAPI 上传图片时会出现 "Unprocessable Entity"错误?

转载 作者:行者123 更新时间:2023-12-02 18:32:02 33 4
gpt4 key购买 nike

我正在尝试上传图片,但 FastAPI 返回时出现了一个我无法理解的错误。

如果我在函数定义中省略“file: UploadFile = File(...)”,它会正常工作。但是当我将 file 添加到函数定义时,它会抛出错误。

这是完整的代码。

@router.post('/', response_model=schemas.PostItem, status_code=status.HTTP_201_CREATED)
def create(request: schemas.Item, file: UploadFile = File(...), db: Session = Depends(get_db)):

new_item = models.Item(
name=request.name,
price=request.price,
user_id=1,
)
print(file.filename)
db.add(new_item)
db.commit()
db.refresh(new_item)
return new_item

Item Pydantic 模型就是

class Item(BaseModel):
name: str
price: float

错误是:
代码 422 错误:无法处理的实体

{
"detail": [
{
"loc": [
"body",
"request",
"name"
],
"msg": "field required",
"type": "value_error.missing"
},
{
"loc": [
"body",
"request",
"price"
],
"msg": "field required",
"type": "value_error.missing"
}
]
}

最佳答案

问题是您的路由需要两种类型的请求正文:

  • 请求:schemas.Item

    • 这是期待 POST 一个 application/json 主体
    • 查看 Request Body FastAPI 文档的部分:“将请求正文读取为 JSON
  • 文件:UploadFile = File(...)

    • 这需要 POST 一个 multipart/form-data
    • 查看 Request Files FastAPI 文档的部分:“FastAPI 将确保从正确的位置读取数据而不是 JSON。...当表单包含文件时,它被编码为 multipart/form-data"

不会起作用,因为它不仅会破坏 FastAPI,还会破坏一般的 HTTP 协议(protocol)。 FastAPI 在 a warning 中提到了这一点使用 File 时:

You can declare multiple File and Form parameters in a path operation, but you can't also declare Body fields that you expect to receive as JSON, as the request will have the body encoded using multipart/form-data instead of application/json.

This is not a limitation of FastAPI, it's part of the HTTP protocol.

常用解决方案,如 Posting a File and Associated Data to a RESTful WebService preferably as JSON 中所讨论, 是:

  1. 将 API 分成 2 个 POST 请求:1 个用于文件,1 个用于元数据
  2. 全部发送到 1 multipart/form-data

幸运的是,FastAPI 支持解决方案 2,结合您的 Item 模型并将文件上传到 1 multipart/form-data。请参阅有关 Request Forms and Files 的部分:

Use File and Form together when you need to receive data and files in the same request.

这是您修改后的路线(我删除了 db,因为它与问题无关):

class Item(BaseModel):
name: str
price: float

class PostItem(BaseModel):
name: str

@router.post('/', response_model=PostItem, status_code=status.HTTP_201_CREATED)
def create(
# Here we expect parameters for each field of the model
name: str = Form(...),
price: float = Form(...),
# Here we expect an uploaded file
file: UploadFile = File(...),
):
new_item = Item(name=name, price=price)
print(new_item)
print(file.filename)
return new_item

Swagger 文档将其呈现为一种形式

swagger UI with form

...现在您应该能够在一个请求中同时发送 Item 参数和文件。

如果您不喜欢将您的 Item 模型拆分为单独的参数(这对于具有许多字段的模型确实很烦人),请参阅 fastapi form data with pydantic model 上的此问答。 .

这是修改后的代码,其中 Item 更改为 ItemForm 以支持接受其字段作为 Form 值而不是 JSON:

class ItemForm(BaseModel):
name: str
price: float

@classmethod
def as_form(cls, name: str = Form(...), price: float = Form(...)) -> 'ItemForm':
return cls(name=name, price=price)

class PostItem(BaseModel):
name: str

@router.post('/', response_model=PostItem, status_code=status.HTTP_201_CREATED)
def create(
item: ItemForm = Depends(ItemForm.as_form),
file: UploadFile = File(...),
):
new_item = Item(name=item.name, price=item.price)
print(new_item)
print(file.filename)
return new_item

Swagger UI 应该仍然相同(所有 Item 字段和文件上传都以一种形式)。

为此:

If I leave out the "file: UploadFile = File(...)" from the function definition, it works correctly

专注于此并不重要,但它起作用了,因为删除 File 会将预期的请求主体变回 application/json 类型,因此 JSON 主体可以工作.

最后,作为旁注,我强烈建议不要使用request 作为路由的参数名称。除了含糊不清(一切都是请求)之外,当 using the Request object directly 时,它可能与 FastAPI 的 request: Request 参数冲突。 .

关于python - 为什么使用 FastAPI 上传图片时会出现 "Unprocessable Entity"错误?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/69292855/

33 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com