使用FastAPI,您可以定义,验证,生成文档和使用任意深度嵌套的模型(这要归功于Pydantic
)。
一、List
字段
您可以将属性定义为子类型。 例如,Python的list
:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: list = []
上面的设定tags
是list
项目类型,尽管它并没有声明每个项目的类型。
二、具有子类型的List
字段
但是Python有一种特定的方法来声明带有子类型的列表:
1. 导入typing
的 List
首先,导入Python中typing
类的List
:
from typing import List
2. 声明List
的子类
声明类型有子类,比如list
,dict
,tuple
:
- 从
typing
导入 - 将子类型用花括号包起来:
[
和]
from typing import List
my_list: List[str]
这就是类型声明的所有标准Python语法。
对具有子类型的模型属性使用相同的标准语法。
因此,在我们的例子中,我们可以设置tags
具体为字符串的列表
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: 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
三、设置类型
但是当我们思考一下,如果tags
里的字符串必须唯一,不能重复。
并且Python有专门的数据类型对于这种唯一的项目,就是set
。
我们可以导入 Set
并且声明 tags
是 set
的类,子类是 str
:
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str = None
price: float
tax: 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}
return results
这样,即使您收到带有重复数据的请求,该请求也会被转换为一组唯一的项目。
而且,每当您输出该数据时,即使源重复,它们也将作为一组唯一项输出。
并且它也会被相应地注释/生成文档。
四、嵌套的模型
每个Pydantic
模型的每一个属性都有一个类型。
而且,这个类型可以自身是另一个Pydantic
模型。
因此,您可以使用特定的属性名称,类型和验证来声明深度嵌套的JSON
对象。并且,可以任意嵌套。
1. 定义一个子模型
例如,我们可以定义Image
类型:
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str name: str
2. 使用子模型作为类型
然后我们可以将其用作属性的类型:
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
image: 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"
}
}
同样地,在FastAPI声明,您将获得:
- 编辑器支持(补全),即使是嵌套模型
- 数据转换
- 数据验证
- 自动文档
五、特殊类型和验证
除了正常的单数类型,如str
,int
,float
等外,您还可以使用从str
继承的更复杂的单数类型。
要查看所有选项,请查看Pydantic's exotic types。 您将在下一章中看到一些示例。
例如,在Image
模型中,我们需要一个url
字段,我们可以将它声明为Pydantic
中的UrlStr
,而不是简单的str
:
from typing import Set
from fastapi import FastAPI
from pydantic import BaseModel, UrlStr
app = FastAPI()
class Image(BaseModel):
url: UrlStr
name: str
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
image: 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
该字符串将被检查为有效的URL
,并在 JSON Schema / OpenAPI
中进行记录。
六、带有子模型列表的属性
您还可以将Pydantic
模型用作list
,set
等的子类型:
from typing import List, Set
from fastapi import FastAPI
from pydantic import BaseModel, UrlStr
app = FastAPI()
class Image(BaseModel):
url: UrlStr
name: str
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
images: 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, Set
from fastapi import FastAPI
from pydantic import BaseModel, UrlStr
app = FastAPI()
class Image(BaseModel):
url: UrlStr
name: str
class Item(BaseModel):
name: str
description: str = None
price: float
tax: float = None
tags: Set[str] = []
images: List[Image] = None
class Offer(BaseModel):
name: str
description: str = None
price: float
items: List[Item]
@app.post("/offers/")
async def create_offer(*, offer: Offer):
return offer
八、全部列表的请求体
如果期望的JSON
主体的顶级值为JSON
数组(Python列表),则可以在函数的参数中声明类型,与Pydantic
模型相同:
images: List[Image]
如下:
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel, UrlStr
app = FastAPI()
class Image(BaseModel):
url: UrlStr
name: str
@app.post("/images/multiple/")
async def create_multiple_images(*, images: List[Image]):
return images
九、编辑器支持
无论在哪里你都可以得到编辑器支持。
即使在列表里的项:
如果您直接使用dict
而不是Pydantic
模型,那么您将无法获得这种编辑器支持。
但是您也不必担心它们,传入的dict
会自动转换,您的输出也会自动转换为JSON
。
十、任意 dict
的主体
您还可以使用某些类型的键和其他类型的值将主体声明为dict
。
无需事先知道有效的字段/属性名称是什么(就像Pydantic
模型一样)。
如果你不知道你将要接受到什么样的key
,用dict
很有用。
其他有用的情况是当您想使用其他类型的键时,例如 int
。
下面来看看这个例子:
在这种情况下,您可以接受任何dict,只要它具有带有float
值的int
键即可:
from typing import Dict
from fastapi import FastAPI
app = FastAPI()
@app.post("/index-weights/")
async def create_index_weights(weights: Dict[int, float]):
return weights
记住:
JSON
只支持str
作为键。但是Pydantic
会自动转换数据
这意味着,即使您的API客户端只能将字符串作为键发送,只要这些字符串包含纯整数,Pydantic就会对其进行转换并验证它们。
网友评论