欢迎您访问365答案网,请分享给你的朋友!
生活常识 学习资料

python:Fastapi请求体-嵌套模型

时间:2023-05-25

请求体 - 字段

字段与使用 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

Copyright © 2016-2020 www.365daan.com All Rights Reserved. 365答案网 版权所有 备案号:

部分内容来自互联网,版权归原作者所有,如有冒犯请联系我们,我们将在三个工作时内妥善处理。