【问题标题】:How to handle nested files with FastAPI?如何使用 FastAPI 处理嵌套文件?
【发布时间】:2022-07-24 20:21:09
【问题描述】:

我正在开发一个网站,其中前端在 React 中完成,后端在 Python 中使用 FastAPI。我制作了一个表单,它需要一些数据并使用 axios 将其发送到后端。看起来是这样的

{
name='Jonathan',
aliases=["Johnny"],
birthdate='2-15-1980',
gender='male', 
height=178 
weight=90 
nationalities=["American", "French"], 
occupations=["Programmer", "Comedian"], 
status='single', 
images=[
  {'attachment': FileList,
   'location': 'Berlin',
   'date': '10-14-2019'
  }
]
}

但是,当我提交它时。 FastApi 似乎从表单中删除了图像。

name='Jonathan',
aliases=["Johnny"],
birthdate='2-15-1980',
gender='male', 
height=178 
weight=90 
nationalities=["American", "French"], 
occupations=["Programmer", "Comedian"], 
status='single', 
images=[
{'attachment': {'0': {}}, 'location': 'Berlin', 'date': '10-14-2019'}
]

这是当前路线的样子

@router.post("/register/user")
def register_user(user_data: UserCreate):
    print(user_data)

我不完全确定发生了什么。我猜这与数据的发送方式及其加密方式有关。我在这里陷入了死胡同。提前致谢。

编辑:这就是 UserCreate Schema 的样子

class CharacterCreate(BaseModel):
    name: str
    aliases: list

    birthdate: Optional[str]
    gender: str
    height: Optional[float]
    weight: Optional[float]

    nationalities: Optional[set[str]]
    occupations: Optional[set[str]]

    status: str
    images: Optional[list]

【问题讨论】:

  • 当您在前端代码中引用FileList 时,您是否检查了浏览器的开发工具(在网络下)实际提交给FastAPI 的内容?我猜你看到的就是你实际提交的,FileList 并不能像你期望的那样序列化。
  • @Chris 用模型编辑了问题
  • @MatsLindh 澄清一下,FileList 似乎是一个内置的 JS 对象,而不是自定义对象。在请求负载中它只显示为images=[object Object]
  • @Chris 是的。这些图像还应该包含一些关于它们的信息
  • @Chris 我看到了那个帖子,但它看起来像使用Form(...) 我需要单独接受每个字段,这会使函数有很多参数。有什么方法可以接受文件作为一个参数,而将表单的其余部分作为另一个参数?

标签: javascript html forms fastapi


【解决方案1】:

根据documentation,您不能在同一个请求中同时拥有JSONFiles / form-data,因为正文是使用multipart/form-data 编码的(当文件)或application/x-www-form-urlencoded(如果只包括Form数据)而不是application/json。看看this answer

因此,解决此问题的一种方法是使用单个参数来保存各种“元数据”,并为文件/图像设置第二个参数。使用Dependency Injection,您可以使用parse_raw 方法根据Pydantic 模型检查接收到的数据,然后再继续到端点。如果抛出ValidationError,则应引发HTTPException (HTTP_422_UNPROCESSABLE_ENTITY),包括错误。下面给出了工作示例。或者,查看this answer 中的方法4

app.py

from fastapi import FastAPI, Form, File, UploadFile, status
import pydantic
from pydantic import BaseModel
from typing import Optional, List
from fastapi.exceptions import HTTPException
from fastapi.encoders import jsonable_encoder
from fastapi import Depends

app = FastAPI()

class User(BaseModel):
    name: str
    aliases: List[str]
    height: Optional[float]
    weight: Optional[float]

def checker(data: str = Form(...)):
    try:
        user = User.parse_raw(data)
    except pydantic.ValidationError as e:
        raise HTTPException(detail=jsonable_encoder(e.errors()), status_code=status.HTTP_422_UNPROCESSABLE_ENTITY)
    return user
    
@app.post("/submit")
def submit(user: User = Depends(checker), files: List[UploadFile] = File(...)):
        return {"User": user, "Uploaded Files": [file.filename for file in files]}

test.py

import requests

url = 'http://127.0.0.1:8000/submit'
files = [('files', open('test_files/a.txt', 'rb')), ('files', open('test_files/b.txt', 'rb'))]
data = {'data' : '{"name": "foo", "aliases": ["alias_1", "alias_2"], "height": 1.80, "weight": 80.5}'}
resp = requests.post(url=url, data=data, files=files) 
print(resp.json())

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-01-21
    • 1970-01-01
    • 2013-07-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多