You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在FastAPI注册接口中同时上传文件与JSON格式学校列表数据?

FastAPI form-data 多学校信息列表传递最优方案

方案一:通过JSON字符串传递学校列表(推荐)

这种方式实现简单,前后端代码量少,只需将学校列表转为JSON字符串放入form-data字段,后端结合Json类型解析为Pydantic模型列表。

1. 修正用户信息模型错误

原模型as_form方法存在参数名错误,修正后:

from pydantic import BaseModel
from fastapi import Form, Depends, UploadFile, File, status
from sqlalchemy.orm import Session
from typing import List, Annotated
from pydantic import Json

class User(BaseModel):
    name: str 
    password: str 
    email: str

    @classmethod
    def as_form(cls, name: str = Form(...), password: str = Form(...),
                email: str = Form(...)) -> 'User':
        return cls(name=name, password=password, email=email)

2. 学校信息模型保持不变

class School(BaseModel):
    school: str 
    country: str

3. 接口定义修改

用Annotated[List[School], Form()]结合Json解析JSON字符串为学校列表:

@router.post("/signup", status_code=status.HTTP_201_CREATED)
async def signup(
    schools: Annotated[List[School], Form()],
    user: User = Depends(User.as_form),
    file: UploadFile = File(),
    session: Session = Depends(db.session)
):
    # 后续业务逻辑:保存用户、学校信息、处理上传文件等
    return {
        "user": user.dict(), 
        "schools": [s.dict() for s in schools], 
        "uploaded_file": file.filename
    }

前端传递要求

form-data需包含以下字段:

  • name/password/email:普通字符串类型
  • schools:值为学校列表的JSON字符串,例如:[{"school":"清华大学","country":"中国"},{"school":"MIT","country":"美国"}]
  • file:待上传的文件

方案二:通过多字段批量传递(适配前端无法生成JSON的场景)

如果前端无法处理JSON字符串,可通过结构化命名的多字段传递学校信息,后端自定义依赖解析为模型列表。

1. 自定义依赖项解析学校列表

from fastapi import Request

async def get_schools_from_form(request: Request) -> List[School]:
    form_data = await request.form()
    schools = []
    # 提取所有学校索引
    school_indexes = set()
    for key in form_data.keys():
        if key.startswith("schools-"):
            parts = key.split("-")
            if len(parts) >= 3:
                school_indexes.add(parts[1])
    # 按索引解析每所学校的信息
    for idx in school_indexes:
        school_name = form_data.get(f"schools-{idx}-school")
        country = form_data.get(f"schools-{idx}-country")
        if school_name and country:
            schools.append(School(school=school_name, country=country))
    return schools

2. 接口使用自定义依赖

@router.post("/signup", status_code=status.HTTP_201_CREATED)
async def signup(
    schools: List[School] = Depends(get_schools_from_form),
    user: User = Depends(User.as_form),
    file: UploadFile = File(),
    session: Session = Depends(db.session)
):
    # 后续业务逻辑
    return {
        "user": user.dict(), 
        "schools": [s.dict() for s in schools], 
        "uploaded_file": file.filename
    }

前端传递要求

form-data需包含以下类型字段:

  • name/password/email:普通字符串类型
  • 多组学校字段:如schools-0-school(第一所学校名称)、schools-0-country(第一所学校国家)、schools-1-school(第二所学校名称)等
  • file:待上传的文件

方案对比

  • 方案一:代码简洁,前后端实现成本低,是最优选择,优先采用。
  • 方案二:适配前端受限场景,但字段命名需严格遵循规则,代码相对繁琐。

内容的提问来源于stack exchange,提问作者giwony

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.09 01:20:29