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

如何用Pydantic设计FastAPI嵌套字典输入模型?写法是否合理?

问题解答

一、当前类设计的问题及修正

你的代码存在几个明显问题,导致当前设计不正确:

  1. 大小写错误:College类里的optional写成小写了,得用从typing导入的大写Optional(你在Person类里已经用对了,这里漏了)。
  2. 类型不匹配:JSON示例里grade是字符串(比如'A'),但你在Class模型里定义成了int,这会直接导致数据校验失败。
  3. 冗余/未明确的字段:College类里的age字段在你的输入JSON里根本没有,如果不是必填项,要么标记成可选,要么直接删掉(看你实际需求)。

修正后的可用代码:

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI()

class Class(BaseModel):
    level: str
    grade: str  # 改成字符串类型,匹配JSON里的字母成绩

class College(BaseModel):
    name: str
    age: Optional[int] = None  # 标记为可选,或者直接删除这个字段
    Classes: Optional[List[Class]] = None  # 修正Optional的大小写

class Person(BaseModel):
    name: str
    description: str
    Colleges: Optional[List[College]] = None

@app.post("/create/", response_model=dict)
def create(person: Person):
    # 这里写你的业务逻辑
    return {'message': 'success'}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

二、更简洁的嵌套模型写法

Pydantic支持在父类里面定义内部嵌套模型,这样就能把整个Person->Colleges->Classes的结构塞进单个类里,不用拆成三个独立的类,代码更紧凑:

from fastapi import FastAPI
from pydantic import BaseModel
from typing import List, Optional

app = FastAPI()

class Person(BaseModel):
    name: str
    description: str
    
    # 直接在Person里定义Class子模型
    class Class(BaseModel):
        level: str
        grade: str
    
    # 接着定义College子模型,引用上面的内部Class
    class College(BaseModel):
        name: str
        age: Optional[int] = None
        Classes: Optional[List['Person.Class']] = None  # 用字符串引用避免前置定义问题
    
    Colleges: Optional[List[College]] = None

# 要是你用Python 3.10+,可以不用字符串引用,直接写Person.Class就行
# 旧版本Python用字符串引用更稳妥

@app.post("/create/", response_model=dict)
def create(person: Person):
    return {'message': 'success'}

if __name__ == "__main__":
    import uvicorn
    uvicorn.run(app, host="127.0.0.1", port=8000)

这种写法的好处:

  • 层级关系一目了然,所有相关模型都封装在Person类里
  • 不会把全局命名空间搞得乱七八糟

另外,Python 3.10+还支持用list[Class] | None代替Optional[List[Class]],语法更简洁:

# Python 3.10+ 简化写法
Classes: list['Person.Class'] | None = None
Colleges: list[College] | None = None

三、其他简化思路

如果你的模型不需要复杂的校验、序列化功能,也可以试试TypedDict,但FastAPI配合Pydantic的BaseModel能提供更强的自动校验、文档生成能力,所以还是更推荐嵌套BaseModel的方式。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 23:04:53