fastapi学习笔记

MirrorYuChen
MirrorYuChen
发布于 2025-01-14 / 7 阅读
0
0

fastapi学习笔记

fastapi学习笔记

1.库安装

>> pip install "fastapi[standard]"

2.快速入门

  • (1) 编写测试代码 main.py
'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from typing import Union
from fastapi import FastAPI

app = FastAPI()

@app.get("/")
def read_root():
  return {"Hello": "World"}

@app.get("/items/{item_id}")
def read_item(item_id: int, q: Union[str, None] = None):
  return {"item_id": item_id, "q": q}

  • (2) 启动当前服务:
>> fastapi dev main.py
 FastAPI   Starting development server 🚀
 
             Searching for package file structure from directories with __init__.py files
             Importing from /home/mirror/workspace/python
 
    module   🐍 main.py
 
      code   Importing the FastAPI app object from the module with the following code:
 
             from main import app
 
       app   Using import string: main:app
 
    server   Server started at http://127.0.0.1:8000
    server   Documentation at http://127.0.0.1:8000/docs
 
       tip   Running in development mode, for production use: fastapi run
 
             Logs:
 
      INFO   Will watch for changes in these directories: ['/home/mirror/workspace/python']
      INFO   Uvicorn running on http://127.0.0.1:8000 (Press CTRL+C to quit)
      INFO   Started reloader process [12766] using WatchFiles
      INFO   Started server process [12769]
      INFO   Waiting for application startup.
      INFO   Application startup complete.
  • (3) 测试服务:网页分别输入如下地址:
http://127.0.0.1:8000
http://127.0.0.1:8000/items/1180

3.路径参数

3.1 简单路径参数

​ 你可以使用 python格式字符串相同语法,来声明路径“参数”或“变量”。

from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id):
  return {"item_id": item_id}

​ 路径参数的值 item_id将会作为参数 item_id传递给你的函数,所以,你可以运行这个示例,然后访问 http://127.0.0.1:8000/items/foo,你将看到如下响应:

{"item_id": "foo"}

3.2 有类型的路径参数

​ 你可以使用标准 python类型声明,在函数中声明路径参数类型:

from fastapi import FastAPI

app = FastAPI

@app.get("/items/{item_id}")
async def read_item(item_id: int):
  return {"item_id": item_id}

​ 这里将 item_id声明为 int类型,编辑器将会支持在你的函数内部进行错误检查及代码补全等。与此同时,当你进行类型声明后,FastAPI会自动帮你进行请求解析,若请求的传参类型不对,将会给你报一个 HTTP错误。

3.3.顺序问题

​ 路径操作是按照顺序来进行的,例如,你期望 /users/me匹配优先级高于 /user/{usr_id},你就需要将 /users/me相关函数写到 /user/{user_id}前面:

from fastapi import FastAPI

app = FastAPI

@app.get("/user/me")
async def read_user_me():
  return {"user_id": "the current user"}

@app.get("/user/{user_id}")
async def read_user(user_id: str):
  return {"user_id": user_id}

​ 类似的,你不能重定义路径操作。

3.4.预定义值

​ 你可以使用标准 pythonEnum来预定义可能的有效路径参数值。具体操作如下:

  • (1) 创建子类继承自 strEnum
  • (2) 通过继承自 str,表明值必须是 str类型;
  • (3) 创建具有固定值的类属性,这些固定值将是可用的有效值;
'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from enum import Enum
from fastapi import FastAPI

class ModelName(str, Enum):
  alexnet = "alexnet"
  resnet = "resnet"
  lenet = "lenet"

app = FastAPI()

@app.get("/models/{model_name}")
async def get_model(model_name: ModelName):
  if model_name is ModelName.alexnet:
    return {"model_name": model_name, "message": "Deep Learning FTW!"}
  
  if model_name.value == "lenet":
    return {"model_name": model_name, "message": "LeCNN all the images"}

  return {"model_name": model_name, "message": "Have some residuals"}

​ 这里使用 is对传入参数与枚举成员 ModelName进行比较,然后使用 model_name.value来获取实际值。

4.1 默认查询参数解析

​ 当你的声明不属于路径参数的其它函数参数时,它们会被自动解释为“查询”参数。

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI

app = FastAPI()

fake_items_db = [{"item_name": "Foo"}, {"item_name", "Bar"}, {"item_name", "Baz"}]

@app.get("/items/")
async def read_item(skip: int = 0, limit: int = 10):
  print(f"skip: {skip}, limit: {limit}")
  return fake_items_db[skip : skip + limit]

​ 访问网页 http://127.0.0.1:8000/items/?skip=0&limit=20,查询被设置为 ?后面的键值对,并通过 &符号进行分隔。当你不传参数时,查询参数为默认值 skip=0, limit=10

4.2 可选参数

​ 相同的方式,你可以通过设置它们默认值为 None来声明可选查询参数:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from typing import Union
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: int = 0, q: Union[str, None] = None):
  print(f"item_id: {item_id}, q: {q}")
  if q:
    return {"item_id": item_id, "q": q}
  return {"item_id": item_id}

​ 访问 URL:http://127.0.0.1:8000/items/1160?q=hello,world

4.3 必须查询参数

​ 当你为为非路径参数声明默认值时,它就不是必须的,当你想将一个参数声明为必须时,只需要不给它任何默认值:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from typing import Union
from fastapi import FastAPI

app = FastAPI()

@app.get("/items/{item_id}")
async def read_item(item_id: str, needy: str):
  return {"item_id": item_id, "needy": needy}

​ 访问 URL: http://127.0.0.1:8000/items/item_id=123456?needy=Hi

5.请求主体

​ 当需要从客户端发送数据到 API,你需要将数据作为请求 body来发送。一个请求 body为从客户端发送到 API的数据,一个响应 body为从 API发送到客户端的数据。

​ 你的 API几乎总是需要发送响应 body,但客户端不必一直发送请求 body,有时它们仅需要请求一个路径,可能带一些请求参数,而不需要发送 body

​ 你需要将你的数据模型声明为继承自 BaseModel的类,然后,使用标准的 Python类型声明其所有属性:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI
from pydantic import BaseModel
from typing import Union

class Item(BaseModel):
  name: str
  description: Union[str, None] = None
  price: float
  tax: Union[float, None] = None

app = FastAPI()

@app.post("/items/")
async def create_item(item: Item):
  item_dict = item.model_dump()
  if item.tax:
    price_with_tax = item.price + item.tax
    item_dict.update({'price_with_tax': price_with_tax})
  return item_dict

​ 访问方法:

  • (1) 命令行:curl工具
curl -X 'POST' \
  'http://127.0.0.1:8000/items/' \
  -H 'Content-Type: application/json' \
  -d '{
  "name": "Example Item",
  "description": "This is an example item",
  "price": 9.99,
  "tax": 1.0
}'
  • (2) Postman:请求方法设置为 POST,地址设置为 http://127.0.0.1:8000/itemsBody设置为 raw,类型设置为 JSON,内容如下:
{
  "name": "Example Item",
  "description": "This is an example item",
  "price": 9.99,
  "tax": 1.0
}

​ 点击 Send,响应如下:

{
    "name": "Example Item",
    "description": "This is an example item",
    "price": 9.99,
    "tax": 1.0,
    "price_with_tax": 10.99
}

6.请求参数和字符串校验

​ FastAPI允许你为参数声明附加信息和校验,让我们先看一个例子:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI
from typing import Union


app = FastAPI()

@app.get("/items/")
async def create_item(q: Union[str, None] = None):
  results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
  if q:
    print(f"q: {q}")
    results.update({"q": q})
  return results

​ 请求参数 q的类型为 Union[str, None],意味着它的类型可以为 str也可以为 None,默认值为 None,所以 FastAPI将知道它不是必须要传的。

6.1 附加校验

​ 即使 q是可选的,但是只要附加校验——“提供它的长度不能超过50个字符”,我们都将强制执行。

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Query
from typing import Union
from typing_extensions import Annotated


app = FastAPI()

@app.get("/items/")
async def create_item(q: Annotated[Union[str, None], Query(max_length=50)] = None):
  results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
  if q:
    print(f"q: {q}")
    results.update({"q": q})
  return results

​ 当添加附加校验后,FastAPI将会做如下内容:

  • (1) 校验数据,并确保数据最大长度为50个字符长度;
  • (2) 当数据未通过校验,会向客户端显示一个明确的错误;
  • (3) 在 OpenAPI路径操作中记录参数(会将其显示在自动文档 UI中);

​ 旧版本中要求使用 Query作为参数默认值:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Query
from typing import Union
from typing_extensions import Annotated


app = FastAPI()

@app.get("/items/")
async def create_item(q: Union[str, None] = Query(default=None, max_length=10)):
  results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
  if q:
    print(f"q: {q}")
    results.update({"q": q})
  return results

​ 这种情况下(不使用 Annotated),必须替换在函数中使用 Query()替换掉缺省值 None,我们现在需要使用参数 Query(default=None)来设置缺省值。

​ 但是 Query版本显式地声明它作为 query参数,然后我们传递更多参数给 Query,这种情况下,max_length参数被用于字符串:

q: Union[str, None] = Query(default=None, max_length=50)

​ 使用 Annotated的优势:

  • (1) 函数参数的默认值是实际默认值,对于 python来说,通常更加直观;
  • (2) 你可以在无需 FastAPI的地方调用相同函数,它将按预期工作。如果有一个必需参数(无默认值),你的编辑器将会报一个错误,Python也会告知你,在运行它时没有传递必需参数;
  • (3) 当你不使用 Annotated而使用旧的默认值风格,如果你在其它无需 FastAPI的地方调用函数,你必须记住将参数传递给函数以使其正常工作,否则值将与你预期不同(例如,QueryInfo或类似值,而不是 str)。并且,你的编辑器也不会报错,Python也不会在运行时报错,只要在内部出错时才会报错。

6.2 添加更多校验

​ 你也可以添加一个参数 min_length,定义一个参数需要匹配的正则表达式 pattern

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Query
from typing import Union
from typing_extensions import Annotated


app = FastAPI()

@app.get("/items/")
async def create_item(
  q: Annotated[
    Union[str, None], 
    Query(min_length=3, max_length=50, pattern="^fixedquery$")
  ] = None
):
  results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
  if q:
    print(f"q: {q}")
    results.update({"q": q})
  return results

​ 这个特殊正则表达式将会检查接收到参数值:

  • ^:以下面字符开始,之前没有字符;
  • fixedquery:具有精确的值 fixedquery
  • $:到此结束,之后不再有任何字符 fixedquery

6.3 必填参数

​ 还有另外一种方法声明参数是必需传的,你只需要将默认值设置未 ...

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Query
from typing import Union
from typing_extensions import Annotated


app = FastAPI()

@app.get("/items/")
async def create_item(
  q: Annotated[
    Union[str, None], 
    Query(min_length=3, max_length=50, pattern="^fixedquery$")
  ] = ...
):
  results = {"items": [{"item_id": "Foo"}, {"item_id": "Bar"}]}
  if q:
    print(f"q: {q}")
    results.update({"q": q})
  return results

6.4 参数列表及缺省值

​ 当你定义查询参数时,Query还可以声明接收值列表及默认值:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Query
from typing import Union, List
from typing_extensions import Annotated

app = FastAPI()

@app.get("/items/")
async def create_item(
  q: Annotated[
    Union[List[int], None], 
    Query(
      title="Query int list",
      description="Query int for the items to search database that have a good match"
    )
  ] = [123, 456]
):
  query_items = {"q": q}
  return query_items

​ 当你访问 http://127.0.0.1:8000/items/,对应响应为:

{
  "q": [
    123,
    456
  ]
}

​ 你也可以使用 list,而不是 List[int],但是 List[int]会检查列表内容是否为整数,而 list单独使用不会。你还可以添加更多参数,如 descriptiontitle等。

6.5 别名函数

​ 当你想要参数是 item-query,但是 item-query不是一个有效的 Python变量,你可以使用 alias,该别名将用于查找参数值:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Query
from typing import Union, List
from typing_extensions import Annotated

app = FastAPI()

@app.get("/items/")
async def create_item(
  q: Annotated[
    Union[str, None], 
    Query(
      alias="item-query"
    )
  ] = None
):
  query_items = {"q": q}
  return query_items

​ 请求 URL为:http://127.0.0.1:8000/items/?item-query=mirror,最终输出结果为:

{
    "q": "mirror"
}

6.6 弃用参数

​ 假设不想要某个参数,但是由于有些客户端正在用它而不得不保留,因此想要在文档中明确的表示它为弃用的。你可以向 Query中传参 deprecated=True

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Query
from typing import Union, List
from typing_extensions import Annotated

app = FastAPI()

@app.get("/items/")
async def create_item(
  q: Annotated[
    Union[str, None], 
    Query(
      alias="item-query",
      deprecated=True
    )
  ] = None
):
  query_items = {"q": q}
  return query_items

​ 打开页面 127.0.0.1:8000/docs,你会看到当前参数被有红色的标注 depreated。你也可以使用 Queryinclude_in_schema参数来标注某个参数是否 OpenAPI文档中展示。

7.路径参数和数字校验

​ 相同的方式,你可以使用 Query为查询参数声明更多验证和元数据,你可以使用 Path声明相同类型的验证和元数据.

7.1 导入Path

​ 首先,从 fastapi中导入 Path,并导入 Annotated

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Query, Path
from typing import Union, List
from typing_extensions import Annotated

7.2 声明元数据

​ 你可以像 Query一样声明所有相同参数,例如,为路径参数 item_id声明一个 title元数据

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Query, Path
from typing import Union, List
from typing_extensions import Annotated

app = FastAPI()

@app.get("/items/{item_id}")
async def create_item(
  item_id: Annotated[
    int, Path(title="The ID of the item to get")
  ],
  q: Annotated[
    Union[str, None],
    Query(alias="item-query")
  ] = None
):
  results = {"item_id": item_id}
  if q:
    results.update({"q": q})
  return results

​ 访问 URLhttp://127.0.0.1:8000/items/2025?item-query=mirror,输出结果为:

{
    "item_id": 2025, 
    "q": "mirror"
}

​ 当参数必须作为路径的一部分,一个路径参数通常是必需的。就算你将其声明为 None或设置一个默认值,这也不起任何作用,它将仍然被需要。

7.3 按需排列参数

​ 如果你使用 Annotated,这可能不那么重要或必要。将 *作为函数的第一个参数,对于 *符号 Python不会做任何事,但是,它将知道所有后续参数应该作为关键字参数(键值对)被调用:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Path
from typing import Union

app = FastAPI()

@app.get("/items/{item_id}")
async def create_item(*,
  item_id: int = Path(title="The ID of the item to get"),
  q: Union[str, None] = None,
  v: Union[str, None] = None
):
  results = {"item_id": item_id}
  if q:
    results.update({"q": q})
  if v:
    results.update({"v": v})
  return results

​ 这样请求时,就无需去在意传参顺序,参数会按照字典进行解析,无论你访问时按照 http://127.0.0.1:8000/items/2025?v=mirror&q=yu访问,还是按照 http://127.0.0.1:8000/items/2025?q=yu&v=mirror都能得到正确结果。当然,使用 Annotated会更好,当没有使用函数参数默认值,你将没有这个问题,你可能也无需使用 *

7.4 数字验证

​ 使用 QueryPath(和其它参数),你可以声明数字约束,这里使用 ge=1item_id将需要为一个大于等于(greater equal)1:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Path
from typing import Union

app = FastAPI()

@app.get("/items/{item_id}")
async def create_item(*,
  item_id: int = Path(title="The ID of the item to get", ge=1),
  q: str
):
  results = {"item_id": item_id}
  if q:
    results.update({"q": q})
  return results

​ 当你访问过程中传入 item_id小于1时,例如:http://127.0.0.1:8000/items/0?q=1024就会报错:

{"detail":[{"type":"greater_than_equal","loc":["path","item_id"],"msg":"Input should be greater than or equal to 1","input":"0","ctx":{"ge":1}}]}

​ 相同的,你可以使用其它约束:

  • gtgreater than
  • gegreater equal
  • ltless than
  • leless equal

8.主体内容

8.1 混合 PathQuery和主体参数

​ 首先,你可以自由地混合 PathQuery和请求主体参数声明,FastAPI将知道做什么。你也可以通过设置主体参数默认值为 None,将其设置为可选项:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Path
from typing import Union
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
  name: str
  description: Union[str, None] = None
  price: float
  tax: Union[float, None] = None
  

@app.put("/items/{item_id}")
async def create_item(*,
  item_id: int = Path(title="The ID of the item to get", ge=1),
  q: Union[str, None] = None,
  item: Union[Item, None] = None
):
  results = {"item_id": item_id}
  if q:
    results.update({"q": q})
  if item:
    results.update({"item": item})
  return results

​ 测试方法:使用 Postman将方法设置为 PUT,地址设置为 http://127.0.0.1:8000/items/100?q=mirroryuBody模式设置为 raw,数据格式设置为 JSON,内容设置为:

{
  "name": "Example Item",
  "description": "This is an example item",
  "price": 9.99,
  "tax": 1.0
}

​ 点击 Send可以得到下面结果:

{
    "item_id": 100,
    "q": "mirroryu",
    "item": {
        "name": "Example Item",
        "description": "This is an example item",
        "price": 9.99,
        "tax": 1.0
    }
}

8.2 多个主体参数

​ 你可以声明多个主体参数,例如 itemuser

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Path
from typing import Union
from pydantic import BaseModel

app = FastAPI()

class Item(BaseModel):
  name: str
  description: Union[str, None] = None
  price: float
  tax: Union[float, None] = None
  
class User(BaseModel):
  username: str
  full_name: Union[str, None] = None
  

@app.put("/items/{item_id}")
async def create_item(*,
  item_id: int = Path(title="The ID of the item to get", ge=1),
  q: Union[str, None] = None,
  item: Union[Item, None] = None,
  user: Union[User, None] = None
):
  results = {"item_id": item_id}
  if q:
    results.update({"q": q})
  if item:
    results.update({"item": item})
  if user:
    results.update({'user': user})
  return results

​ 测试方法和上面一样,不过主体内容需要更改如下:

{
  "item": {
    "name": "Example Item",
    "description": "This is an example item",
    "price": 9.99,
    "tax": 1.0
  },
  "user": {
    "username": "mirror",
    "full_name": "chenjingyu"
  }  
}

​ 输出结果为:

{
    "item_id": 100,
    "q": "mirroryu",
    "item": {
        "name": "Example Item",
        "description": "This is an example item",
        "price": 9.99,
        "tax": 1.0
    },
    "user": {
        "username": "mirror",
        "full_name": "chenjingyu"
    }
}

8.3 主体中的奇异值

​ QueryPath可以为请求和路径参数来定义额外数据,同样的,FastAPI提供了等效的 Body。例如,扩展先前的模型,在相同主体中,除了 itemuser外,你可能想要有另外一个键 importance,如果使用默认声明的方式,FastAPI会将其视为请求与参数,这时,你需要使用另外一个关键字 Body

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Path, Body
from typing import Union
from pydantic import BaseModel
from typing_extensions import Annotated

app = FastAPI()

class Item(BaseModel):
  name: str
  description: Union[str, None] = None
  price: float
  tax: Union[float, None] = None
  
class User(BaseModel):
  username: str
  full_name: Union[str, None] = None
  

@app.put("/items/{item_id}")
async def create_item(*,
  item_id: int = Path(title="The ID of the item to get", ge=1),
  q: Union[str, None] = None,
  item: Item,
  user: User,
  importance: Annotated[
    int, Body()
  ]
):
  results = {"item_id": item_id, "importance": importance}
  if q:
    results.update({"q": q})
  if item:
    results.update({"item": item})
  if user:
    results.update({'user': user})
  return results

​ 请求的 Body内容设置如下:

{
  "item": {
    "name": "Example Item",
    "description": "This is an example item",
    "price": 9.99,
    "tax": 1.0
  },
  "user": {
    "username": "mirror",
    "full_name": "chenjingyu"
  },
  "importance": 30
}

​ PUT结果如下:

{
    "item_id": 100,
    "importance": 30,
    "q": "mirroryu",
    "item": {
        "name": "Example Item",
        "description": "This is an example item",
        "price": 9.99,
        "tax": 1.0
    },
    "user": {
        "username": "mirror",
        "full_name": "chenjingyu"
    }
}

8.4 嵌入单个主体参数

​ 假设你只有一个 Pydantic model格式 Item类型的 item主体参数,默认情况下,FastAPI会直接假设它为主体参数,但是,如果你希望它接收一个带有键 itemJson(内部包含 model内容),就像声明额外的主体参数一样,你可以使用特殊 Body参数 embed

item: Item = Body(enbed=True)

​ 例如:

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Path, Body
from typing import Union
from pydantic import BaseModel
from typing_extensions import Annotated

app = FastAPI()

class Item(BaseModel):
  name: str
  description: Union[str, None] = None
  price: float
  tax: Union[float, None] = None

@app.put("/items/{item_id}")
async def create_item(*,
  item_id: int = Path(title="The ID of the item to get", ge=1),
  item: Annotated[Item, Body(embed=True)],
):
  results = {"item_id": item_id, "item": item}
  return results

​ 那么请求的主体内容需要写成:

{
  "item": {
    "name": "Example Item",
    "description": "This is an example item",
    "price": 9.99,
    "tax": 1.0
  }
}

​ 而不是:

{
  "name": "Example Item",
  "description": "This is an example item",
  "price": 9.99,
  "tax": 1.0
}

8.5 字段信息

​ 你可以使用 Query,Path和Body在路径操作函数参数中声明附加验证和元数据,同样的,你也可以使用 PydanticField来声明 Pydantic模型内部的校验和元数据。

'''
Author: chenjingyu
Date: 2024-12-24 15:38:23
Contact: 2458006466@qq.com
Description: main
'''
from fastapi import FastAPI, Path, Body
from typing import Union
from pydantic import BaseModel, Field
from typing_extensions import Annotated

app = FastAPI()

class Item(BaseModel):
  name: str
  description: Union[str, None] = Field(
    default=None, title="The description of the item", max_length=300
  )
  price: float = Field(gt=0, description="The price must be greater than zero")
  tax: Union[float, None] = None

@app.put("/items/{item_id}")
async def create_item(*,
  item_id: int = Path(title="The ID of the item to get", ge=1),
  item: Annotated[Item, Body(embed=True)],
):
  results = {"item_id": item_id, "item": item}
  return results

​ 对模型属性使用 Field,可以为模型属性添加附加约束或元数据,FiledQueryPathBody工作方式类似,它们有相同的参数。

9.参考资料


评论