请求体 #

什么是请求体? #

请求体是客户端发送给服务器的数据,通常用于 POST、PUT、PATCH 等请求。

text
┌─────────────────────────────────────────────────────────────┐
│                    请求体位置                                │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   POST /items HTTP/1.1                                      │
│   Content-Type: application/json                            │
│                                                             │
│   {                          ← 请求体                        │
│       "name": "Item 1",                                     │
│       "price": 10.5                                         │
│   }                                                         │
│                                                             │
└─────────────────────────────────────────────────────────────┘

Pydantic 模型 #

基本模型 #

python
from pydantic import BaseModel

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

使用模型 #

python
from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None

@app.post('/items/')
def create_item(item: Item):
    return item

模型方法 #

python
@app.post('/items/')
def create_item(item: Item):
    item_dict = item.model_dump()      # 转换为字典
    item_json = item.model_dump_json() # 转换为 JSON 字符串
    return item_dict

字段类型 #

基本类型 #

python
from pydantic import BaseModel

class Item(BaseModel):
    name: str                    # 字符串
    price: float                 # 浮点数
    quantity: int                # 整数
    is_available: bool           # 布尔值
    tags: list[str]              # 字符串列表
    metadata: dict[str, str]     # 字典

可选类型 #

python
from typing import Optional

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    # 或使用 Python 3.10+ 语法
    description: str | None = None

默认值 #

python
class Item(BaseModel):
    name: str
    price: float = 0.0
    quantity: int = 1
    tags: list[str] = []

字段验证 #

Field 函数 #

python
from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str = Field(..., min_length=2, max_length=50)
    price: float = Field(..., gt=0, description='Price must be positive')
    quantity: int = Field(default=1, ge=0)
    tax: float | None = Field(default=None, le=0.5)

字段验证约束 #

text
┌─────────────────────────────────────────────────────────────┐
│                    字段验证约束                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   字符串:                                                   │
│   min_length    最小长度                                    │
│   max_length    最大长度                                    │
│   pattern       正则表达式                                  │
│                                                             │
│   数值:                                                     │
│   gt    大于          ge    大于等于                        │
│   lt    小于          le    小于等于                        │
│   multiple_of    倍数                                       │
│                                                             │
│   列表:                                                     │
│   min_length    最少元素数                                  │
│   max_length    最多元素数                                  │
│                                                             │
│   通用:                                                     │
│   default       默认值                                      │
│   default_factory    默认工厂函数                           │
│   title         标题                                        │
│   description   描述                                        │
│   examples      示例                                        │
│                                                             │
└─────────────────────────────────────────────────────────────┘

字符串验证示例 #

python
from pydantic import BaseModel, Field

class User(BaseModel):
    username: str = Field(
        ...,
        min_length=3,
        max_length=20,
        pattern='^[a-zA-Z0-9_]+$',
        description='Username must be alphanumeric with underscores'
    )
    email: str = Field(
        ...,
        pattern=r'^[\w\.-]+@[\w\.-]+\.\w+$'
    )

数值验证示例 #

python
class Product(BaseModel):
    name: str
    price: float = Field(..., gt=0, description='Price must be positive')
    discount: float = Field(default=0, ge=0, le=1)
    quantity: int = Field(default=0, ge=0)
    rating: float = Field(default=5.0, ge=0, le=5)

列表验证示例 #

python
class Order(BaseModel):
    items: list[str] = Field(..., min_length=1, max_length=10)
    quantities: list[int] = Field(default=[], min_length=1)

特殊类型 #

EmailStr #

python
from pydantic import BaseModel, EmailStr

class User(BaseModel):
    email: EmailStr

HttpUrl #

python
from pydantic import BaseModel, HttpUrl

class Website(BaseModel):
    url: HttpUrl

日期时间类型 #

python
from datetime import datetime, date, time, timedelta
from pydantic import BaseModel

class Event(BaseModel):
    created_at: datetime
    event_date: date
    start_time: time
    duration: timedelta

枚举类型 #

python
from enum import Enum
from pydantic import BaseModel

class Status(str, Enum):
    pending = 'pending'
    approved = 'approved'
    rejected = 'rejected'

class Item(BaseModel):
    status: Status

嵌套模型 #

模型嵌套 #

python
from pydantic import BaseModel

class Image(BaseModel):
    url: str
    name: str

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    image: Image | None = None

@app.post('/items/')
def create_item(item: Item):
    return item

请求体:

json
{
    "name": "Item 1",
    "price": 10.5,
    "image": {
        "url": "http://example.com/image.jpg",
        "name": "Product Image"
    }
}

列表嵌套 #

python
class Item(BaseModel):
    name: str
    price: float

class Order(BaseModel):
    items: list[Item]
    total: float

@app.post('/orders/')
def create_order(order: Order):
    return order

深层嵌套 #

python
class Address(BaseModel):
    street: str
    city: str
    country: str

class User(BaseModel):
    name: str
    address: Address

class Order(BaseModel):
    user: User
    items: list[Item]

自定义验证器 #

field_validator #

python
from pydantic import BaseModel, field_validator

class User(BaseModel):
    name: str
    username: str
    
    @field_validator('username')
    @classmethod
    def username_alphanumeric(cls, v: str) -> str:
        if not v.isalnum():
            raise ValueError('must be alphanumeric')
        return v.lower()

model_validator #

python
from pydantic import BaseModel, model_validator

class User(BaseModel):
    password: str
    confirm_password: str
    
    @model_validator(mode='after')
    def passwords_match(self):
        if self.password != self.confirm_password:
            raise ValueError('passwords do not match')
        return self

验证器示例 #

python
from pydantic import BaseModel, field_validator

class Item(BaseModel):
    name: str
    price: float
    
    @field_validator('name')
    @classmethod
    def name_must_not_be_empty(cls, v: str) -> str:
        if not v.strip():
            raise ValueError('name cannot be empty')
        return v.strip()
    
    @field_validator('price')
    @classmethod
    def price_must_be_positive(cls, v: float) -> float:
        if v <= 0:
            raise ValueError('price must be positive')
        return round(v, 2)

请求体示例 #

添加示例 #

python
from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str = Field(..., examples=['Foo'])
    description: str | None = Field(None, examples=['A very nice Item'])
    price: float = Field(..., examples=[35.4])
    tax: float | None = Field(None, examples=[3.2])

模型示例 #

python
class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    
    model_config = {
        'json_schema_extra': {
            'examples': [
                {
                    'name': 'Foo',
                    'description': 'A very nice Item',
                    'price': 35.4,
                    'tax': 3.2,
                }
            ]
        }
    }

请求体字段 #

Body 函数 #

python
from fastapi import FastAPI, Body
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
    name: str
    description: str | None = None
    price: float

@app.put('/items/{item_id}')
def update_item(
    item_id: int,
    item: Item,
    importance: int = Body(..., gt=0)
):
    return {'item_id': item_id, 'item': item, 'importance': importance}

嵌入请求体 #

python
@app.put('/items/{item_id}')
def update_item(item_id: int, item: Item = Body(..., embed=True)):
    return {'item_id': item_id, 'item': item}

请求体格式:

json
{
    "item": {
        "name": "Foo",
        "price": 45.2
    }
}

多个请求体 #

多个模型 #

python
class Item(BaseModel):
    name: str
    price: float

class User(BaseModel):
    username: str
    full_name: str | None = None

@app.put('/items/{item_id}')
def update_item(item_id: int, item: Item, user: User):
    return {'item_id': item_id, 'item': item, 'user': user}

请求体格式:

json
{
    "item": {
        "name": "Foo",
        "price": 45.2
    },
    "user": {
        "username": "john",
        "full_name": "John Doe"
    }
}

请求体 + 表单 + 文件 #

python
from fastapi import FastAPI, Form, File, UploadFile
from pydantic import BaseModel

app = FastAPI()

@app.post('/items/')
def create_item(
    name: str = Form(...),
    price: float = Form(...),
    file: UploadFile = File(...)
):
    return {
        'name': name,
        'price': price,
        'filename': file.filename
    }

模型配置 #

Config 类 #

python
from pydantic import BaseModel, ConfigDict

class Item(BaseModel):
    model_config = ConfigDict(
        str_strip_whitespace=True,
        str_min_length=1,
        validate_assignment=True,
        extra='forbid'
    )
    
    name: str
    price: float

常用配置 #

text
┌─────────────────────────────────────────────────────────────┐
│                    模型配置选项                              │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│   str_strip_whitespace    去除字符串空白                     │
│   str_min_length          字符串最小长度                     │
│   str_max_length          字符串最大长度                     │
│   validate_assignment     赋值时验证                         │
│   extra                   额外字段处理                       │
│                          'ignore' 忽略                       │
│                          'forbid' 禁止                       │
│                          'allow' 允许                        │
│   alias_generator         别名生成器                         │
│   populate_by_name        允许通过字段名填充                  │
│                                                             │
└─────────────────────────────────────────────────────────────┘

完整示例 #

python
from datetime import datetime
from typing import Optional
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel, Field, EmailStr, field_validator

app = FastAPI()

class Address(BaseModel):
    street: str = Field(..., min_length=5)
    city: str = Field(..., min_length=2)
    country: str = Field(..., min_length=2)

class User(BaseModel):
    username: str = Field(
        ...,
        min_length=3,
        max_length=20,
        pattern='^[a-zA-Z0-9_]+$'
    )
    email: EmailStr
    full_name: Optional[str] = Field(None, min_length=2)
    age: int = Field(..., ge=0, le=150)
    address: Optional[Address] = None
    created_at: datetime = Field(default_factory=datetime.now)
    
    @field_validator('username')
    @classmethod
    def username_lowercase(cls, v: str) -> str:
        return v.lower()

class UserCreate(User):
    password: str = Field(..., min_length=8)

users_db: dict[str, User] = {}

@app.post('/users/', response_model=User, status_code=201)
def create_user(user: UserCreate):
    if user.username in users_db:
        raise HTTPException(status_code=400, detail='Username already exists')
    user_data = user.model_dump(exclude={'password'})
    users_db[user.username] = User(**user_data)
    return users_db[user.username]

@app.get('/users/{username}', response_model=User)
def get_user(username: str):
    if username not in users_db:
        raise HTTPException(status_code=404, detail='User not found')
    return users_db[username]

下一步 #

现在你已经掌握了请求体处理,接下来学习 Pydantic 基础,深入了解数据验证!

最后更新:2026-03-29