我有以下代码示例:
from fastapi import File, UploadFile, Request, FastAPI, Depends
from typing import List
from fastapi.responses import HTMLResponse
from pydantic import BaseModel, Field
from typing import Optional
app = FastAPI()
class BaseBox(BaseModel):
l: float=Field(...)
t: float=Field(...)
r: float=Field(...)
b: float=Field(...)
class BaseInput(BaseModel):
boxes: List[BaseBox] = Field(...)
words: List[str] = Field(...)
width: Optional[float] = Field(...)
height: Optional[float] = Field(...)
@app.post("/submit")
def submit(
base_input: BaseInput = Depends(),
file: UploadFile = File(...), # Add this line to accept a file
):
return {
"JSON Payload": base_input,
"Filename": file.filename,
}
@app.get("/")
def main(request: Request):
return {"status":"alive"}
字符串
但有些如何我不能使它工作.我使用交互式API文档,但我总是得到一个错误.你认为我必须发送2个文件,而不是?我也尝试与
curl -X 'POST' \
'http://localhost:8007/submit?width=10&height=10' \
-H 'accept: application/json' \
-H 'Content-Type: multipart/form-data' \
-F '[email protected];type=image/png' \
-F 'boxes={
"l": 0,
"t": 0,
"r": 0,
"b": 0
}' \
-F 'words=test,test2,tes3,test'
型
但我总是得到错误"POST /submit?width=10&height=10 HTTP/1.1" 422 Unprocessable Entity
。
1条答案
按热度按时间wd2eg0qa1#
从您提供的代码中可以看出,您已经看过this answer了,这就是您最终应该找到的解决方案。
但是,让我解释一下你的例子中的代码有什么问题。你同时提交了文件和查询数据,或者,至少,这是你一直试图实现的。在端点中定义一个查询参数,例如,作为
str
或int
,或Pydantic模型沿着,并在端点中的参数上使用Depends()
来指示BaseModel
中定义的字段被期望作为查询参数,在这两种情况下,但是,当您直接在端点或BaseModel
中将参数定义为List
(例如List[int]
或List[str]
)时,您应该**使用Query
**显式定义它,如here和here所解释和演示的。虽然Pydantic模型在过去不允许使用Query
字段,并且必须在单独的依赖类中实现查询参数解析,如this answer和this answer中所示,这一点最近已经改变,因此,可以使用BaseModel
类将Query()
Package 在Field()
中,如this answer中所示。工作示例1
字符串
在您的示例中,您似乎也有一个
List
查询参数,该参数需要一个字典/JSON对象列表作为值。然而,使用查询参数无法实现。如果您尝试在上面的工作示例中定义这样的参数(例如,boxes: List[BaseBox] = Field (Query(...))
),则在尝试运行FastAPI应用程序时会遇到以下错误:AssertionError:Param:
boxes
只能是请求体,使用Body()
如果您将参数定义为
boxes: List[BaseBox] = Field (...)
,沿着在端点中定义file: UploadFile = File(...)
(就像您在代码中已经做的那样),即使应用程序在尝试向该端点提交请求时会照常开始运行(例如,通过Swagger UI autodocs at/docs
),您将收到一个422 Unprocessable Entity
错误,其中包含一条具有类似含义的消息,说Input should be a valid dictionary or object to extract fields from
。这是因为,在第一种情况下,查询参数不能期望字典数据(除非您遵循针对任意查询数据描述的here和here方法,您需要自己解析,我不建议这样做),而在第二种情况下,由于在端点中定义了
file: UploadFile = File(...)
字段,请求正文被编码为multipart/form-data
发送;但是,HTTP协议不支持同时发送Form和JSON数据(再次参见this answer)。但是,如果您从端点删除了
UploadFile
参数,则请求应该成功通过,因为请求主体将被终止为application/json
(在提交请求时查看Swagger UI中的Content-Type
请求头)。但是,在这种情况下,您应该使用POST
请求-因此,使用@app.post('/')
定义端点,例如,不是GET
,因为带有GET
/HEAD
方法的请求不应该有主体(Requests usingGET
method should only be used to request data; they shouldn't include data)。工作示例2
型
同时发布File和JSON body(包括
List
字典)如果您仍然需要在FastAPI POST请求中添加文件和JSON主体,我强烈建议您查看this answer的方法3和4**。下面提供的示例基于链接答案中的这两种方法,并演示如何将文件与JSON数据一起发布,这些数据还包括字典列表,就像在你的例子中一样。请查看链接的答案,了解更多关于如何测试这些方法的细节和Python和JavaScript中的示例。在你的例子中,你需要将查询参数与主体字段分开,并在端点中定义查询参数(如前面提供的链接答案中所解释的),或者在单独的Pydantic模型中,如下所示。
工作示例3(基于this answer的方法3)
在Swagger UI
/docs
中,由于data
是一个Form
参数,并表示为单个字段,因此您需要将该字段中的Base
数据作为字典传递,该字典将在data
Form
参数中作为str
提交。测试示例:型
有关如何测试的更多信息,请参阅上面的链接答案。
型
工作示例4(基于this answer的方法4)
这种方法的优点是需要更少的代码来实现预期的结果,并且在Swagger UI
/docs
的请求主体部分中表示了Base
模型(使用自动生成的输入示例),从而可以更清晰地查看数据并更轻松地发布数据。同样,请查看上面的链接答案以了解有关这种方法的更多详细信息。型