FastAPI 教程翻译 - 用户指南 10 - 请求主体 - 嵌套模型
FastAPI Tutorial - User Guide - Body - Nested Models
With FastAPI, you can define, validate, document, and use arbitrarily deeply nested models (thanks to Pydantic).
使用 FastAPI,您可以定义、验证、文档和使用任意深度嵌套的模型(感谢 Pydantic)。
List fields
列表字段
You can define an attribute to be a subtype. For example, a Python 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 = []
@app.put("/items/{item_id}")
async def update_item(*, item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
This will make tags
be a list of items. Although it doesn’t declare the type of each of the items.
这将使 tags
成为一个列表。尽管它没有声明每个项目的类型。
List fields with subtype
具有子类型的列表字段
But Python has a specific way to declare lists with subtypes:
Python 有一种特定的方法来声明带有子类型的列表:
Import typing’s List
导入 typing 的 List
First, import List
from standard Python’s typing
module:
首先,从标准 Python 的 typing 模块中导入 List:
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
Declare a List
with a subtype
声明带有子类型的 List
To declare types that have subtypes, like list
, dict
, tuple
:
声明具有子类型的类型,例如 list
、dict
、tuple
:
-
Import them from the
typing
module从
typing
模块导入 -
Pass the subtype(s) as “type arguments” using square brackets:
[
and]
使用方括号将子类型作为『类型实参』:
[
和]
from typing import List
my_list: List[str]
That’s all standard Python syntax for type declarations.
这就是类型声明的所有标准 Python 语法。
Use that same standard syntax for model attributes with subtypes.
对具有子类型的模型属性使用相同的标准语法。
So, in our example, we can make tags
be specifically a “list of strings”:
因此,在我们的示例中,我们可以将 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
Set types
设置类型
But then we think about it, and realize that tags shouldn’t repeat, they would probably be unique strings.
但是随后我们考虑了一下,意识到标签不应该重复,它们可能是唯一的字符串。
And Python has a special data type for sets of unique items, the set
.
而且 Python 具有一组特殊的数据类型来存储唯一项,即 set
。
Then we can import Set
and declare tags
as a set
of str
:
然后我们可以导入 Set
并将 tags
声明为 str
的 set
:
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
With this, even if you receive a request with duplicate data, it will be converted to a set of unique items.
这样,即使您收到带有重复数据的请求,该请求也将被转换为一组唯一的项目。
And whenever you output that data, even if the source had duplicates, it will be output as a set of unique items.
而且,每当您输出该数据时,即使源重复,它们也将作为一组唯一项输出。
And it will be annotated / documented accordingly too.
而且它也会获得相应的注释 / 文档。
Nested Models
嵌套模型
Each attribute of a Pydantic model has a type.
Pydantic 模型的每个属性都有一个类型。
But that type can itself be another Pydantic model.
但是该类型本身可以是另一种 Pydantic 模型。
So, you can declare deeply nested JSON object
s with specific attribute names, types and validations.
因此,您可以使用特定的属性名称、类型和验证来声明深度嵌套的 JSON 对象。
All that, arbitrarily nested.
所有这些,任意嵌套。
Define a submodel
定义子模型
For example, we can define an Image
model:
例如,我们可以定义一个 Image 模型:
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
Use the submodel as a type
使用子模型作为类型
And then we can use it as the type of an attribute:
然后我们可以将其用作属性的类型:
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
This would mean that FastAPI would expect a body similar to:
这意味着 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"
}
}
Again, doing just that declaration, with FastAPI you get:
同样,仅使用 FastAPI 进行声明,您将获得:
-
Editor support (completion, etc), even for nested models
编辑器支持(完成等),甚至对于嵌套模型
-
Data conversion
数据转换
-
Data validation
数据验证
-
Automatic documentation
自动文档
Special types and validation
特殊类型和验证
Apart from normal singular types like str
, int
, float
, etc. You can use more complex singular types that inherit from str
.
除了正常的单类型(如 str
、int
、float
等)外,您还可以使用从 str 继承的更复杂的单类型。
To see all the options you have, checkout the docs for Pydantic’s exotic types. You will see some examples in the next chapter.
要查看所有选项,请查看文档 Pydantic的奇异类型。您将在下一章中看到一些示例。
For example, as in the Image
model we have a url
field, we can declare it to be instead of a str
, a Pydantic’s HttpUrl
:
例如,在 Image
模型中,我们有一个 url
字段,我们可以声明它为 str
,而不是 Pydantic 的 HttpUrl
:
from typing import 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: 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
The string will be checked to be a valid URL, and documented in JSON Schema / OpenAPI as such.
该字符串将被检查为有效的 URL,并获得 JSON 模式 / OpenAPI 的文档。
Attributes with lists of submodels
具有子模型列表的属性
You can also use Pydantic models as subtypes of list
, set
, etc:
您还可以将 Pydantic 模型用作 list
、set
等的子类型:
from typing import List, 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: 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
This will expect (convert, validate, document, etc) a JSON body like:
这将期望获得(转换、验证、文档等)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"
}
]
}
Info
信息
Notice how the
images
key now has a list of image objects.请注意,
images
键现在如何具有图像对象列表。
Deeply nested models
深度嵌套模型
You can define arbitrarily deeply nested models:
您可以定义任意深度嵌套的模型:
from typing import List, 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: 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
Info
信息
Notice how
Offer
as a list ofItem
s, which in turn have an optional list ofImage
s请注意,如何使
offer
包含Item
的列表,而Item
又包含Image
的可选列表。
Bodies of pure lists
纯列表请求主体
If the top level value of the JSON body you expect is a JSON array
(a Python list
), you can declare the type in the parameter of the function, the same as in Pydantic models:
如果您期望的 JSON 主体的顶层值为 JSON 的 array
(Python 的 list
),则可以在函数的参数中声明类型,与 Pydantic 模型相同:
images: List[Image]
as in:
如:
from typing import List
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
@app.post("/images/multiple/")
async def create_multiple_images(*, images: List[Image]):
return images
Editor support everywhere
编辑器无处不在
And you get editor support everywhere.
而且您到处都能获得编辑器支持。
Even for items inside of lists:
甚至是列表中的元素:
You couldn’t get this kind of editor support if you where working directly with dict
instead of Pydantic models.
如果您直接使用 dict
而不是 Pydantic 模型,则无法获得这种编辑器支持。
But you don’t have to worry about them either, incoming dicts are converted automatically and your output is converted automatically to JSON too.
但是您也不必担心它们,传入的 dict
会自动转换,您的输出也会自动转换为 JSON。
Bodies of arbitrary dict
s
任意 dict
的请求主体
You can also declare a body as a dict
with keys of some type and values of other type.
您还可以使用某些类型的键和值将请求主体声明为 dict
。
Without having to know beforehand what are the valid field/attribute names (as would be the case with Pydantic models).
无需事先知道有效的字段 / 属性名是什么(就像 Pydantic 模型那样)。
This would be useful if you want to receive keys that you don’t already know.
如果您想接收未知的密钥,这将很有用。
Other useful case is when you want to have keys of other type, e.g. int
.
其他有用的情况是当您想使用其他类型的键时,例如 int
。
That’s what we are going to see here.
这就是我们在这里看到的。
In this case, you would accept any dict
as long as it has int
keys with float
values:
在这种情况下,您将接受任何具有值为 float
键为 int
的 dict
:
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
Tip
提示
Have in mind that JSON only supports
str
as keys.请记住,JSON 仅支持将
str
作为键。But Pydantic has automatic data conversion.
但是 Pydantic 具有自动数据转换功能。
This means that, even though your API clients can only send strings as keys, as long as those strings contain pure integers, Pydantic will convert them and validate them.
这意味着,即使您的 API 客户端只能将字符串作为键发送,只要这些字符串包含纯整数,Pydantic 就会对其进行转换并验证它们。
And the
dict
you receive asweights
will actually haveint
keys andfloat
values.而您的
weights
收到的dict
实际上将具有int
键和float
值。
Recap
回顾
With FastAPI you have the maximum flexibility provided by Pydantic models, while keeping your code simple, short and elegant.
使用 FastAPI,您将拥有 Pydantic 模型提供的最大灵活性,同时使您的代码简短和美观。
But with all the benefits:
并且有下列所有的好处:
-
Editor support (completion everywhere!)
编辑器支持(无处不在!)
-
Data conversion (a.k.a. parsing / serialization)
数据转换(也称为解析 / 序列化)
-
Data validation
数据验证
-
Schema documentation
模式文档
-
Automatic docs
自动文档