翼度科技»论坛 编程开发 python 查看内容

FastAPI快速入门2 Pydantic&错误处理

5

主题

5

帖子

15

积分

新手上路

Rank: 1

积分
15
2.1 Pydantic简介

Pydantic使用python类型注解进行数据验证和配置管理。这是一款能让您更精确地处理数据结构的工具。例如,到目前为止,我们一直依赖字典来定义项目中的典型配方。有了Pydantic,我们可以这样定义配方:
  1. from pydantic import BaseModel
  2. class Recipe(BaseModel):
  3.     id: int
  4.     label: str
  5.     source: str
  6. raw_recipe = {'id': 1, 'label': 'Lasagna', 'source': 'Grandma Wisdom'}
  7. structured_recipe = Recipe(**raw_recipe)
  8. print(structured_recipe.id)
  9. #> 1
复制代码
Recipe 类继承自Pydantic BaseModel,我们可以使用标准Python类型提示来定义每个预期字段及其类型。
除了使用类型模块的标准类型外,您还可以像这样递归地使用Pydantic模型:
  1. from pydantic import BaseModel
  2. class Car(BaseModel):
  3.     brand: str
  4.     color: str
  5.     gears: int
  6. class ParkingLot(BaseModel):
  7.     cars: List[Car]  # recursively use `Car`
  8.     spaces: int
复制代码
结合这些功能,您可以定义非常复杂的对象。这只是Pydantic功能的皮毛,以下是对其优势的快速总结:

  • 无需学习新的微语言(这意味着它能很好地与集成开发环境/精简器配合使用)
  • 既可用于 "验证该请求/响应数据",也可用于加载配置
  • 验证复杂的数据结构--Pydantic 提供极为精细的验证器
  • 可扩展--您可以创建自定义数据类型
  • 可与Python数据类一起使用
  • 速度非常快
2.2 Pydantic与FastAPI结合使用

ch02/main.py
  1. from fastapi import FastAPI, APIRouter, Query
  2. from typing import Optional
  3. from schemas import RecipeSearchResults, Recipe, RecipeCreate
  4. from recipe_data import RECIPES
  5. app = FastAPI(title="Recipe API", openapi_url="/openapi.json")
  6. api_router = APIRouter()
  7. @api_router.get("/", status_code=200)
  8. def root() -> dict:
  9.     """
  10.     Root GET
  11.     """
  12.     return {"msg": "Hello, World!"}
  13. # Updated using to use a response_model
  14. # https://fastapi.tiangolo.com/tutorial/response-model/
  15. @api_router.get("/recipe/{recipe_id}", status_code=200, response_model=Recipe)
  16. def fetch_recipe(*, recipe_id: int) -> dict:
  17.     """
  18.     Fetch a single recipe by ID
  19.     """
  20.     result = [recipe for recipe in RECIPES if recipe["id"] == recipe_id]
  21.     if result:
  22.         return result[0]
  23. # Updated using the FastAPI parameter validation `Query` class
  24. # # https://fastapi.tiangolo.com/tutorial/query-params-str-validations/
  25. @api_router.get("/search/", status_code=200, response_model=RecipeSearchResults)
  26. def search_recipes(
  27.     *,
  28.     keyword: Optional[str] = Query(
  29.         None,
  30.         min_length=3,
  31.         openapi_examples={
  32.             "chickenExample": {
  33.                 "summary": "A chicken search example",
  34.                 "value": "chicken",
  35.             }
  36.         },
  37.     ),
  38.     max_results: Optional[int] = 10
  39. ) -> dict:
  40.     """
  41.     Search for recipes based on label keyword
  42.     """
  43.     if not keyword:
  44.         # we use Python list slicing to limit results
  45.         # based on the max_results query parameter
  46.         return {"results": RECIPES[:max_results]}
  47.     results = filter(lambda recipe: keyword.lower() in recipe["label"].lower(), RECIPES)
  48.     return {"results": list(results)[:max_results]}
  49. # New addition, using Pydantic model `RecipeCreate` to define
  50. # the POST request body
  51. @api_router.post("/recipe/", status_code=201, response_model=Recipe)
  52. def create_recipe(*, recipe_in: RecipeCreate) -> dict:
  53.     """
  54.     Create a new recipe (in memory only)
  55.     """
  56.     new_entry_id = len(RECIPES) + 1
  57.     recipe_entry = Recipe(
  58.         id=new_entry_id,
  59.         label=recipe_in.label,
  60.         source=recipe_in.source,
  61.         url=recipe_in.url,
  62.     )
  63.     RECIPES.append(recipe_entry.dict())
  64.     return recipe_entry
  65. app.include_router(api_router)
  66. if __name__ == "__main__":
  67.     # Use this for debugging purposes only
  68.     import uvicorn
  69.     uvicorn.run(app, host="0.0.0.0", port=8001, log_level="debug")
复制代码
ch02/schemas.py:
  1. from pydantic import BaseModel, HttpUrl
  2. from typing import Sequence
  3. class Recipe(BaseModel):
  4.     id: int
  5.     label: str
  6.     source: str
  7.     url: HttpUrl
  8. class RecipeSearchResults(BaseModel):
  9.     results: Sequence[Recipe]
  10. class RecipeCreate(BaseModel):
  11.     label: str
  12.     source: str
  13.     url: HttpUrl
  14.     submitter_id: int
复制代码
/recipe/{recipe_id} 已更新为包含response_model字段。在这里,我们通过Pydantic来定义JSON响应的结构。
新的食谱类继承自pydantic BaseModel,每个字段都使用标准类型提示进行定义,除了 url 字段,它使用了 Pydantic HttpUrl helper。这将强制执行预期的 URL 组件,例如方案(http 或 https)的存在。
我们在 /search endpointsearch 端点响应中添加了响应模型 RecipeSearchResults。我们引入了 FastAPI Query 类,它允许我们为查询参数添加额外的验证和要求,例如最小长度。请注意,由于我们设置了示例字段,因此当您"尝试"时,文档页面上会显示该示例字段。
RecipeSearchResults 类使用Pydantic的递归功能定义了一个字段,该字段指向我们之前定义的另一个Pydantic 类,即Recipe类。我们指定结果字段将是一个Recipes的Sequence(这是一个支持 len 和 getitem 的可迭代类)。
为了将函数设置为处理POST请求,我们只需调整api_router装饰器。请注意,我们还将HTTP status_code设置为 201,因为我们正在创建资源。
recipe_in 字段是 POST 请求正文。通过指定 Pydantic 模式,我们能够自动验证传入的请求,确保其主体符合我们的模式。
为了持久保存创建的配方,我们正在进行原始列表追加。当然,这只是一个玩具示例,在服务器重启时不会持久化数据。在本系列的后面,我们将介绍数据库。
RecipeCreate 模式包含一个新字段:submitter_id,因此我们要将它与 Recipe 模式区分开来。
请务必在本地通过交互式文档运行应用程序时尝试创建一些新菜谱。
参考资料

2.3 错误处理


  • 错误处理之前:


  • 新增错误处理
ch02/main2.py
  1. from fastapi import FastAPI, APIRouter, Query, HTTPException  # 1
  2. # skipping...
  3. @api_router.get("/recipe/{recipe_id}", status_code=200, response_model=Recipe)
  4. def fetch_recipe(*, recipe_id: int) -> Any:
  5.     """
  6.     Fetch a single recipe by ID
  7.     """
  8.     result = [recipe for recipe in RECIPES if recipe["id"] == recipe_id]
  9.     if not result:
  10.         # the exception is raised, not returned - you will get a validation
  11.         # error otherwise.
  12.         # 2
  13.         raise HTTPException(
  14.             status_code=404, detail=f"Recipe with ID {recipe_id} not found"
  15.         )
  16.     return result[0]
复制代码


来源:https://www.cnblogs.com/testing-/p/18247338
免责声明:由于采集信息均来自互联网,如果侵犯了您的权益,请联系我们【E-Mail:cb@itdo.tech】 我们会及时删除侵权内容,谢谢合作!

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x

举报 回复 使用道具