具体来说,我希望以下示例能够工作:
from typing import List from pydantic import BaseModel from fastapi import FastAPI, UploadFile, File app = FastAPI() class DataConfiguration(BaseModel): textColumnNames: List[str] idColumn: str @app.post("/data") async def data(dataConfiguration: DataConfiguration, csvFile: UploadFile = File(...)): pass # read requested id and text columns from csvFile
如果这不是 POST 请求的正确方法,请告诉我如何从上传的 CSV 文件中选择所需的列FastAPI。
根据 FastAPI 文档:
您可以在路径操作中声明多个 Form 参数,但不能同时声明您希望以 JSON 形式接收的 Body 字段,因为请求的正文将使用 application/x-www-form-urlencoded 而不是 application/json 进行编码(当表单包含文件时,它会被编码为multipart/form-data)。
这不是 FastAPI 的限制,它是 HTTP 协议的一部分。
请注意,您需要先安装 python-multipart — 如果您还没有这样做,因为上传的文件是作为“表单数据”发送的。例如:
pip install python-multipart
还应该注意的是,在下面的示例中,端点是使用普通 def 定义的,但您也可以使用 async def (根据您的需要)。请查看此答案,了解有关 FastAPI 中 def 与 async def 的更多详细信息。
如果您正在寻找如何上传文件和字典/JSON 数据列表,请看看这个答案,以及这个答案和这个工作示例的答案(主要基于以下一些方法)。
如此处所述,可以使用文件和表单同时定义文件和表单字段。下面是一个工作示例。如果您有大量参数并希望与端点分开定义它们,请查看此答案,了解如何使用依赖项类或 Pydantic 模型来声明贴花表单字段。
app.py
from fastapi import Form, File, UploadFile, Request, FastAPI from typing import List from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates app = FastAPI() templates = Jinja2Templates(directory="templates") @app.post("/submit") def submit( name: str = Form(...), point: float = Form(...), is_accepted: bool = Form(...), files: List[UploadFile] = File(...), ): return { "JSON Payload": { "name": name, "point": point, "is_accepted": is_accepted, }, "Filenames": [file.filename for file in files], } @app.get("/", response_class=HTMLResponse) def main(request: Request): return templates.TemplateResponse("index.html", {"request": request})
您可以通过访问下面的模板来测试上面的示例http://127.0.0.1:8000。如果您的模板不包含任何 Jinja 代码,您也可以返回一个简单的 HTMLResponse。
templates/index.html
<!DOCTYPE html> <html> <body> <form method="post" action="http://127.0.0.1:8000/submit" enctype="multipart/form-data"> name : <input type="text" name="name" value="foo"><br> point : <input type="text" name="point" value=0.134><br> is_accepted : <input type="text" name="is_accepted" value=True><br> <label for="files">Choose file(s) to upload</label> <input type="file">
您也可以测试此示例使用 /docs 处的交互式 OpenAPI/Swagger UI 自动文档,例如 http://127.0.0.1:8000/docs,或使用Python请求,如下图:
test.py
from typing import List from pydantic import BaseModel from fastapi import FastAPI, UploadFile, File app = FastAPI() class DataConfiguration(BaseModel): textColumnNames: List[str] idColumn: str @app.post("/data") async def data(dataConfiguration: DataConfiguration, csvFile: UploadFile = File(...)): pass # read requested id and text columns from csvFile
还可以使用 Pydantic 模型以及依赖项来通知 /submit 端点(在下面的示例中)参数化变量 base 依赖于 Base 类。请注意,此方法需要将基础数据作为查询(而不是主体)参数,然后对其进行验证并转换为 Pydantic 模型(在本例中,即基础模型)。另外,请注意,永远不应该通过查询字符串传递敏感数据,因为这会带来严重的安全风险 - 请查看此答案以获取有关该主题的更多详细信息。
返回 Pydantic 模型实例时(在本例中,这是基础)来自 FastAPI 端点(例如下面的 /submit 端点),它将使用 jsonable_encoder 在幕后自动转换为 JSON 字符串,如本节中详细说明的 回答。但是,如果您希望在端点内自行将模型转换为 JSON 字符串,您可以使用 Pydantic 的 model_dump_json() (在 Pydantic V2 中),例如,base.model_dump_json(),并直接返回自定义响应,正如之前链接的答案中所解释的;因此,避免使用 jsonable_encoder。否则,为了自己将模型转换为字典,您可以使用 Pydantic 的 model_dump() (在 Pydantic V2 中),例如,base.model_dump(),或简单地 dict(base) (请注意,从返回一个 dict 对象一个端点,FastAPI 仍然会在幕后使用 jsonable_encoder,如上面链接的答案中所述)。您还可以查看此答案以获取相关的 Pydantic 方法和文档。
除了使用 Pydantic 模型作为查询参数之外,还可以直接在端点中定义查询参数,如本答案所示,以及这个答案和这个答案。
除了基本查询参数之外,以下 /submit 端点还需要在请求中编码为 multipart/form-data 的文件body.
app.py
pip install python-multipart
同样,您可以使用下面的模板进行测试,这次使用 JavaScript 来修改form 元素,以便将表单数据作为查询参数传递到 URL 而不是表单数据。
templates/index.html
from fastapi import Form, File, UploadFile, Request, FastAPI from typing import List from fastapi.responses import HTMLResponse from fastapi.templating import Jinja2Templates app = FastAPI() templates = Jinja2Templates(directory="templates") @app.post("/submit") def submit( name: str = Form(...), point: float = Form(...), is_accepted: bool = Form(...), files: List[UploadFile] = File(...), ): return { "JSON Payload": { "name": name, "point": point, "is_accepted": is_accepted, }, "Filenames": [file.filename for file in files], } @app.get("/", response_class=HTMLResponse) def main(request: Request): return templates.TemplateResponse("index.html", {"request": request})
以上是如何在 FastAPI POST 请求中接受 JSON 和文件上传?的详细内容。更多信息请关注PHP中文网其他相关文章!