请求体 - 字段
字段与使用 Query、Path 和 Body 在路径操作函数中声明额外的校验和元数据的方式相同,可以使用 Pydantic 的 Field 在 Pydantic 模型内部声明校验和元数据。
注意点:Field 是直接从 pydantic 导入的,而不是像其他的(Query,Path,Body 等)都从 fastapi 导入。
首先导入Field:
from pydantic import Field
其次开始声明模型定义字段:
from pydantic import Field, baseModelclass Items(baseModel): name: str full_name: Optional[str] = Field(None, min_length=2) description: Optional[str] = Field(None, max_length=100) price: float = Field(..., gt=0) gender: str = Field(..., alias="g") tax: int = Field(None, title="用于文档中", description="在文档中显示")
注释信息:
min_length=2 是设置字段的最小长度max_length=100 是设置字段最大长度gt=0 是大于0 [ ge大于等于、lt小于、le小于等于]alias="g" 是取别名title="用于文档中" 显示在生成的docs文档中description="在文档中显示" 显示在生成的docs文档中
然后开始定义接口:
from typing import Optionalfrom fastapi import FastAPIfrom fastapi import Bodyfrom pydantic import Field, baseModelclass Items(baseModel): name: str full_name: Optional[str] = Field(None, min_length=2) description: Optional[str] = Field(None, max_length=100) price: float = Field(..., gt=0) gender: str = Field(..., alias="g") tax: int = Field(None, title="用于文档中", description="在文档中显示")app = FastAPI()@app.put("/items/{item_id}")def read_field(item_id: int, item: Items = Body(..., embed=True)): return {"item_id": item_id, "item": item}
然后启动服务:
lifeng@192 fastapiProject % uvicorn field_main:app --reloadINFO: Will watch for changes in these directories: ['/Users/lifeng/python-projects/python-code/fastapiProject']INFO: Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)INFO: Started reloader process [45277] using statreloadINFO: Started server process [45279]INFO: Waiting for application startup.INFO: Application startup complete.WARNING: StatReload detected file change in 'field_main.py'. Reloading...INFO: Shutting downINFO: Waiting for application shutdown.INFO: Application shutdown complete.INFO: Finished server process [45279]INFO: Started server process [45376]INFO: Waiting for application startup.INFO: Application startup complete.INFO: 127.0.0.1:55549 - "PUT /items/1 HTTP/1.1" 200 OK
最后请求接口:
PUT :http://127.0.0.1:8000/items/1
传入请求参数:
{ "item": { "name": "haha", "price": 2.8, "g": "eee" }}
返回响应结果:
{ "item_id": 1, "item": { "name": "haha", "full_name": null, "description": null, "price": 2.8, "g": "eee", "tax": null }}
请求体 - 嵌套模型
就是给属性(字段)定义为拥有子元素的类型,如:name: list 或 name: List),还有就是嵌套子模型(可以直接理解为字段又嵌套一个子字段),如:image: Optional[Image] = None等。
from fastapi import FastAPIfrom typing import Optional, List, Setfrom pydantic import baseModel, Fieldclass Image(baseModel): url: str name: strclass User(baseModel): name: str full_name: Optional[str] = Field(None) age: int = Field(..., ge=0) tags: List[str] = [] email: Set[str] = set() image: Imageapp = FastAPI()@app.put("/items/{item_id}")def read_items(item_id: int, user: User): results = {"item_id": item_id, "user": user} return results
上述例子User就是声明的模型,Image也是声明的模型,只是Image用在User中,故被称为子模型(嵌套模型),是image属性(字段)拥有的子元素的类型
tags和email是属性含子类型的类型image属于子模型用作类型email属性定义为集合的原因,是可以过滤重复值,保证唯一值,但是在传参时,按列表类型传即可
请求接口:
PUT :http://127.0.0.1:8000/items/1
请求参数:
{ "name": "haha", "age": 11, "tags": [ "1", "2" ], "email": [ "1", "2" ], "image": { "url": "http://example.com/baz.jpg", "name": "heihei" }}
请求结果:
{ "item_id": 1, "user": { "name": "haha", "full_name": null, "age": 11, "tags": [ "1", "2" ], "email": [ "1", "2" ], "image": { "url": "http://example.com/baz.jpg", "name": "heihei" } }}
如果你遇到字段需要定义为url,就像这样的:
from pydantic import baseModelclass Image(baseModel): url: str name: str
那就直接把url声明为HttpUrl,而不是声明为str:
from pydantic import baseModel, HttpUrlclass Image(baseModel): url: HttpUrl name: str
因为声明为HttpUrl,该字符串将被检查是否为有效的 URL,若检查出不是有效的URL,则抛出异常:
{ "detail": [ { "loc": [ "body", "image", "url" ], "msg": "invalid or missing URL scheme", "type": "value_error.url.scheme" } ]}
有些时候可能会遇到要在子参数中传数组,数组中要传多个参数,那这个时候就需要给子模型定义类型,也称子模型的属性:
from fastapi import FastAPIfrom typing import Listfrom pydantic import baseModel, Field, HttpUrlclass Image(baseModel): url: HttpUrl name: strclass User(baseModel): name: str age: int = Field(..., ge=0) images: List[Image]app = FastAPI()@app.put("/items/{item_id}")def read_items(item_id: int, user: User): results = {"item_id": item_id, "user": user} return results
请求接口:
PUT :http://127.0.0.1:8000/items/1
请求参数:
{ "name": "haha", "age": 11, "images": [ { "url": "http://example.com/baz.jpg", "name": "heihei" }, { "url": "http://example.com/baz.jpg", "name": "heihei" }, { "url": "http://example.com/baz.jpg", "name": "heihei" } ]}
请求结果:
{ "item_id": 1, "user": { "name": "haha", "age": 11, "images": [ { "url": "http://example.com/baz.jpg", "name": "heihei" }, { "url": "http://example.com/baz.jpg", "name": "heihei" }, { "url": "http://example.com/baz.jpg", "name": "heihei" } ] }}
你还可以自定义任意深度的嵌套模型:
from fastapi import FastAPIfrom typing import List, Optional, Setfrom pydantic import baseModel, HttpUrlapp = FastAPI()class Image(baseModel): url: HttpUrl name: strclass Item(baseModel): name: str description: Optional[str] = None price: float tax: Optional[float] = None tags: Set[str] = set() images: List[Image]class Offer(baseModel): name: str description: Optional[str] = None price: float items: List[Item]@app.post("/items/")async def read_items(offer: Offer): return offer
请求接口:
POST :http://127.0.0.1:8000/items
请求参数:
{ "name": "haha", "price": 3.9, "items": [ { "name": "heihei", "price": 4.99, "tags": [ 1, 2, 3, 3, 3, 3 ], "images": [ { "url": "http://example.com/baz.jpg", "name": "heihei" } ] } ]}
请求结果:
{ "name": "haha", "description": null, "price": 3.9, "items": [ { "name": "heihei", "description": null, "price": 4.99, "tax": null, "tags": [ "1", "3", "2" ], "images": [ { "url": "http://example.com/baz.jpg", "name": "heihei" } ] } ]}
从请求结果可以看到,请求参数中的tags是一个数组,其实在接口中是一个集合,集合有去重功能,所以返回的结果自然就只有一个3了。
今天先聊到这里吧,以上总结或许能帮助到你,或许帮助不到你,但还是希望能帮助到你,如有疑问、歧义,直接私信留言会及时修正发布;非常期待你的一键 3 连【 点赞、收藏、分享 】哟,谢谢!
未完成,待续……
一直在努力,希望你也是!
微信搜索公众号:就用python