FastAPI 教程翻译 - 用户指南 10 - 请求主体 - 嵌套模型

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:

声明具有子类型的类型,例如 listdicttuple

  • 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 声明为 strset

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 objects 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.

除了正常的单类型(如 strintfloat 等)外,您还可以使用从 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 模型用作 listset 等的子类型:

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 of Items, which in turn have an optional list of Images

请注意,如何使 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 dicts

任意 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 键为 intdict

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 as weights will actually have int keys and float 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

    自动文档

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,针对您的问题,我可以给出以下Java代码示例,演示如何通过API接口发送最外层嵌套form-data格式的参数。 ``` import java.io.File; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.UUID; import okhttp3.MediaType; import okhttp3.MultipartBody; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.RequestBody; import okhttp3.Response; public class PostFormData { public static void main(String[] args) throws IOException { // 生成一个随机的boundary final String boundary = UUID.randomUUID().toString().replace("-", ""); // 定义请求体 final MediaType mediaType = MediaType.parse("multipart/form-data; boundary=" + boundary); final RequestBody requestBody = new MultipartBody.Builder(boundary) .setType(MultipartBody.FORM) .addFormDataPart("param1", "value1") .addFormDataPart("param2", "value2") .addFormDataPart("file", "test.txt", RequestBody.create(MediaType.parse("application/octet-stream"), new File("test.txt"))) .build(); // 定义请求 final Request request = new Request.Builder() .url("http://example.com/api") .post(requestBody) .build(); // 发送请求 final OkHttpClient client = new OkHttpClient(); final Response response = client.newCall(request).execute(); // 打印响应 System.out.println(response.code()); System.out.println(response.body().string()); } } ``` 在这个示例中,我们使用了OkHttp库发送API请求。首先,我们生成一个随机的boundary,用于分隔不同的form-data参数。然后,我们使用MultipartBody.Builder创建请求体,设置请求体类型为multipart/form-data,并添加最外层的form-data参数(param1和param2),以及文件参数(file)。请注意,文件参数需要使用RequestBody.create方法创建一个RequestBody对象,传入文件的MimeType和文件对象。 接下来,我们定义请求对象,设置URL和请求体,并使用OkHttpClient发送请求。最后,我们打印响应体,包括响应码和响应内容。 请注意,这只是一个简单的示例,实际应用中可能需要进行更多的错误处理和数据验证。同时,确保将URL、form-data参数和文件参数设置为适合您的实际情况。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值