随笔 - 37,  文章 - 0,  评论 - 0,  阅读 - 9966

多个参数

混用Path、Query和请求体参数

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

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    
@app.put("/items/{item_id}")
async def update_item(
            *,
            item_id: int = Path(..., title = "The ID of the item to get", ge=0, le=1000),
            q: Optional[str] = None,
            item: Optional[Item] = None
            ):
    results = {"item_id": item_id}
    if q:
        results.update({"q": q})
    if item:
        results.update({"item": item})
    return results

多个请求体参数

上例中,路径操作预期JSON请求体中的Item包含如下属性:

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2
}

但也可以声明多个请求体参数,例如itemuser

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

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    
class User(BaseModel):
    username :  str
    full_name : Optional[str] = None
    
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item, user: User):
    results = {"item_id": item_id, "item": item, "user": user}
    return results

本例中,FastAPI能够识别函数中有多个请求体参数,因此,它把参数名作为请求体的键,并返回如下请求体:

{
    "item": {
            "name": "Foo",
            "description": "The pretender",
            "price": 42.0,
            "tax": 3.2
    },
    "user": {
            "username": "dave",
            "full_name": "Dave Grohl"
    }
}

fastapi会自动转换请求中的数据,因此itemuser参数会接收指定的内容。

请求体中的单值

除了QueryPath可以为查询参数与路径参数定义更多数据之外,fastapi还提供了类似的Body函数。例如,扩展上述模型,除了itemuser之外,还要在同一请求体中,添加另一个键importance,如果直接声明该参数,因为importance是单值,fastapi会把它识别为查询参数,此时,就需要使用Body让fastapi把它当做请求体的键。

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

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    
class User(BaseModel):
    username: str
    full_name: Optional[str] = None
    
    
@appput("/items/{item_id}"):
async def update_item(item_id: int ,item: Item, user: User, importance: int = Body(...)):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    return results

此时,fastapi返回如下请求体:

{
    "item": {
        "name": "Foo",
        "description": "The Pretender",
        "price": 42.0,
        "tax": 3.2
    },
    "user": {
        "username": "dave",
        "full_name": "Dave Grohl"
    },
    "importance": 5
}

多个请求体参数和查询参数

除了请求体参数外,还可以声明更多查询参数,默认情况下,单值会被解释为查询参数,因此不必显示添加Query,只需要添加一下代码:

q: str = None

代码如下:

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

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    
    
class User(BaseModel):
    username: str
    full_name: Optional[str] = None
    
@app.put("/items/{item_id}")
async def update_item(
    *,
    item_id: int,
    item: Intem,
    user: User,
    importance: int = Body(..., gt=0),
    q: Optional[str] = None
):
    results = {"item_id": item_id, "item": item, "user": user, "importance": importance}
    if q:
        results.update({"q": q})
    return results

嵌套单个请求体参数

假设只有一个使用pydantic模型Item的请求体参数item,默认情况下,fastapi会直接调用请求体,但是,如果希望JSON中包含item键,且模型内容都在该键之下,就要参照声明更多请求体参数的方式,使用Bodyembed参数:

item: Item = Body(..., embed=True)

代码如下:

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

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item = Body(..., embed=True)):
    results = {"item_id": item_id, "item": item}
    return result

本例中,fastapi预期如下请求体:

{
    "item": {
        "name": "Foo",
        "description": "The pretender",
        "price": 42.0,
        "tax": 3.2
    }
}

字段

与在路径操作函数中使用QueryPathBody声明校验与元数据的方式一样,可以使用Pydantic的Field在Pydantic模型内部声明校验和元数据。

声明模型属性

使用Field定义模型属性:

from typing import Optional
from fastapi import Body, FastAPI
from pydantic import BaseModel, Field

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = Field(
        None, title="The description of the item", max_length=300
    )
    price: float = Field(..., gt=0, description="The price must be greater than zero")
    tax: Optional[float] = None
    
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item = Body(..., embed=True)):
    results = {"item_id": item_id, "item": item}
    return results

嵌套模型

List字段

模型属性可以定义为子类型

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

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: list = []
    
    
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

tags是由多个元素组成的列表,但上例未声明列表内元素的类型。

带类型参数的list字段

声明包含listdicttuple等类型参数的类型:

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

app = FastAPI()

class Item(BaseModel):
    name: str
    desciption: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: List[str] = []
    
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

Set类型

标签(tags)不能重复,每个标签字符串都应该是唯一的,python提供了专门保存一组唯一元素的数据类型,集合(set),导入Set,并把tags声明为由str组成的set

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

app = FastAPI()

class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    freturn results
    

收到的请求中包含重复数据时,会被转换为只包含唯一元素的集合,而且,每次输出数据时,即使源数据中有重复项,输出的也是值包含唯一元素的集合,并且还会在文档中进行相应地注释/存档。

嵌套模型

pydantic模型的每个属性都有自己的类型,而且,这些属性的类型也可以是pydantic模型,因此,pydantic模型可以声明拥有特定属性名、类型和校验的深度嵌套JSON对象,所以这些对象,都可以嵌套。

定义子模型:

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

app = FastAPI()

class Image(BaseModel):
    url: str
    name: str
    
class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Set[str] = []
    image: Optional[Image] = None
    
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

FastAPI返回如下请求体:

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": ["rock", "metal", "bar"],
    "image": {
        "url": "http://example.com/baz.jpg",
        "name": "The Foo live"
    }
}

特殊类型与校验

除了strintfloat等普通单值类型外,还可以使用从str继承的复杂单值类型。

例如:把Image模型的url字段声明为Pydantic的HttpUrl,而不是str。

from typing import Optional, Set
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()

class Image(BaseModel):
    url: HttpUrl
    name: str
    
class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    image: Optional[Image] = None
    
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return result

包含子模型列表的属性

listset的子类型也可以是Pydantic模型。

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

app = FastAPI()

class Image(BaseModel):
    url: HttpUrl
    name: str
    
class Image(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Set[str] = set()
    image: Optional[List[Image]] = None
    
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
    results = {"item_id": item_id, "item": item}
    return results

JSON请求体以如下方式转、校验并存档:

{
    "name": "Foo",
    "description": "The pretender",
    "price": 42.0,
    "tax": 3.2,
    "tags": [
        "rock",
        "metal",
        "bar"
    ],
    "images": [
        {
            "url": "http://example.com/baz.jpg",
            "name": "The Foo live"
        },
        {
            "url": "http://example.com/dave.jpg",
            "name": "The Baz"
        }
    ]
}

深度嵌套模型

from typing import List, Optional, Set

from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl

app = FastAPI()


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


class Item(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    tax: Optional[float] = None
    tags: Set[str] = set()
    images: Optional[List[Image]] = None


class Offer(BaseModel):
    name: str
    description: Optional[str] = None
    price: float
    items: List[Item]


@app.post("/offers/")
async def create_offer(offer: Offer):
    return offer

 

posted on   司徒轩宇  阅读(218)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示