• Python框架篇(2):FastApi-参数接收和验证


     @提示: 如果想获取文章中具体的代码信息,可在微信搜索【猿码记】回复 【fastapi】即可。

    1.参数接收

    1.1 路径参数(不推荐)

    1.代码清单

    app/router下,新增demo_router.py文件,内容如下:

    from fastapi import APIRouter

    router = APIRouter(
        prefix="/demo",
        tags=["演示接口"]
    )

    @router.get("/path/{order_id}")
    async def pathParamReceive(order_id: int):
        """
        路径参数接收演示
        """

        return {
            "接受结果": order_id,
        }
    • 1

    @注意:当我们定义参数类型时,FastAPI 接受参数时,会自动进行"解析",如果类型不一致,则会报错。

    2.请求验证
    # 正常传参
    ➜  curl http://127.0.0.1:8000/demo/path/12222
    {"接受结果":12222}
    # 当传参类型不匹配时,接口定义是:int
    ➜  curl http://127.0.0.1:8000/demo/path/hello
    {"detail":[{"loc":["path","order_id"],"msg":"value is not a valid integer","type":"type_error.integer"}]}
    # 当什么都不传时
    ➜ curl http://127.0.0.1:8000/demo/path/
    {"detail":"Not Found"}
    • 1
    3.顺序大坑

    假如我们定义两个接口,带路径参数的:/path/{order_id}和不带路径参数的:/path/test,可能会因为顺序问题,导致我们无法正常访问/path/test,例如路由注册时代码如下:

    ...
    @router.get("/path/{order_id}")
    async def pathParamReceive(order_id: int):
        """
        路径参数接收-演示-带路径参数
        """

        return {
            "接受结果": order_id,
        }


    @router.get("/path/test")
    async def pathParamReceive2():
        """
        路径参数接收-演示-不带路径参数
        """

        return {
            "msg""hello",
        }
    • 1

    然后进行访问:

    # 带路径参数的可以正常访问
    ➜  curl http://127.0.0.1:8000/demo/path/99999
    {"接受结果":99999}
    # 不带路径参数的可以正常访问
    ➜ curl http://127.0.0.1:8000/demo/path/test
    {"detail":[{"loc":["path","order_id"],"msg":"value is not a valid integer","type":"type_error.integer"}]}
    • 1

    通过替换两个函数位置,就可以正常访问了, 感觉比较奇葩,不推荐使用,只做了解即可。更多使用方法可见官方文档: https://fastapi.tiangolo.com/zh/tutorial/path-params/

    1.2 查询参数

    1.代码清单

    app/router下,新增demo_router.py文件,内容如下:

    from typing import Union
    ...
    @router.get("/query/receive")
    @router.get("/query/receive")
    async def queryParamReceive(username: str, sex: str = '男', city: Union[str, None] = None):
        """
        查询参数接受-演示
        """

        return {
            "msg""查询参数接收",
            "result": {
                "username": username,
                "sex": sex,
                "city": city,
            }
        }
    ...    
    • 1
    2.参数约束
    • username: str: 代表参数 username为必填字段;
    • sex: str = '男': 代表参数 sex为选填字段,并且有默认值 ;
    • city: Union[str, None] = None: 代表参数 city为选填字段, 并无默认值; Uniontyping 模块中的一个泛型类,用于表示多个类型中的一个;

    @注意: 当参数有默认值时,顺序一定要放在没有默认值参数后面,否则会提示语法错误:SyntaxError: non-default argument follows default argument

    3.请求验证
    alt

    1.3 请求体(推荐)

    使用请求体接受参数,一般分为两个步骤:

    • 第一步: 使用 Pydantic模型声明一个请求体(其实就是 class);
    • 第二步: 路由函数的参数绑定上这个模型;

    @注意:工作中比较常用的参数接收方式,推荐使用~

    1.定义模型

    文件位置: app/parameter/demo_param.py

    from typing import Union
    # 导入pydantic对应的模型基类
    from pydantic import BaseModel

    class DemoParam(BaseModel):
        """
        请求体参数对应的模型
        """

        user_name: str
        age: int
        city: Union[str, None]
    • 1
    2.优化导入

    文件位置: app/parameter/__init__.py

    from app.parameter.demo_param import DemoParam
    • 1
    3.使用

    文件位置: app/router/demo_router.py

    # from app.parameter.demo_param import DemoParam 如果没有优化导入,需要用这种方式导入
    from app.parameter import DemoParam # 如果没有优化导入,这行会报错

    router = APIRouter(
        prefix="/demo",
        tags=["演示接口"]
    )


    @router.post("/query/receive")
    async def bodyReceive(body: DemoParam):
        """
        请求体参数接受-演示
        """

        return {
            "msg""请求体参数接受",
            "result": {
                "body": body,
            }
        }
    • 1
    4.验证
    # 必填参数user_name,不传时
    curl -X 'POST' \
      'http://127.0.0.1:8000/demo/query/body/receive' \
      -H 'accept: application/json' \
      -H 'Content-Type: application/json' \
      -d '{
      "age": 99,
      "city": "北京"
    }'


    {"detail":[{"loc":["body","user_name"],"msg":"field required","type":"value_error.missing"}]}


    # 必填参数user_name,传值时
    ➜ curl -X 'POST' \
      'http://127.0.0.1:8000/demo/query/body/receive' \
      -H 'accept: application/json' \
      -H 'Content-Type: application/json' \
      -d '{
      "user_name": "娃哈哈",
      "age": 99,
      "city": "北京"
    }'

    {"msg":"请求体参数接受","result":{"body":{"user_name":"娃哈哈","age":99,"city":"北京"}}}

    # 必填参数user_name,传空时
    ➜  curl -X 'POST' \
      'http://127.0.0.1:8000/demo/query/body/receive' \
      -H 'accept: application/json' \
      -H 'Content-Type: application/json' \
      -d '{
      "user_name": "",
      "age": 99,
      "city": "北京"
    }'

    {"msg":"请求体参数接受","result":{"body":{"user_name":"","age":99,"city":"北京"}}}
    • 1

    2.参数验证

    Python中推荐使用成熟的第三方库进行数据验证,这样不仅可以少写一些if .. elif..,还能让代码的可读性更强;

    2.1 Pydantic介绍

    Pydantic 是一个 Python 库,用于数据验证和设置,特别是用于验证数据模型。它通过声明性的方式定义数据模型,并提供了强大的数据验证和转换功能。Pydantic 最初是为 FastAPI 框架设计的,但它也可以在其他 Python 项目中独立使用。

    @注意: 文中使用的pydantic版本为: 1.10.11, 貌似不同的版本,可能会存在差异;具体可参见官方文档: https://docs.pydantic.dev/latest/

    使用Pydantic 的本质,其实就是如何编写对应的数据验证规则,下面列举一些常用的规则:

    2.2 常用验证

    下面列举一些常用的验证规则:

    • 基本数据类型: int, float, str, bool;
    • 可选参数: Optional[type] 表示可选参数, Union[x, None]也可以表示可选;
    • 整数范围: 结合 conint函数判断数字范围 ,如 age: conint(ge=18, le=30); ge:大于等于、gt:大于、le:小于等于、lt:小于
    • 字符长度: 结合 constr函数判断字符长度,如: constr(min_length=6, max_length=10);
    • 正则表达式: 使用 constr函数中的参数 regex ,可以用于进行正则表达式验证;
    • 枚举验证: 使用 Enum 定义枚举类,验证。
    • 列表类型: 使用 List[type] 来限制列表值的类型,并尝试把参数转成对应的类型。
    • 字典类型: Dict[key_type, value_type] 来限制字典 keyval类型,并尝试把参数转成对应的类型。
    from enum import Enum
    from typing import Union, Optional, List, Dict

    # 导入pydantic对应的模型基类
    from pydantic import BaseModel, constr, conint


    class GenderEnum(str, Enum):
        """
        性别枚举
        """

        male = "男"
        female = "女"


    class PydanticVerifyParam(BaseModel):
        """
        用来学习使用pydantic模型验证
        """

        user_name: str  # 基本类型
        age: conint(ge=18, le=30)  # 整数范围:18 <= age <= 30
        password: constr(min_length=6, max_length=10)  # 字符长度
        phone: constr(regex=r'^1\d{10}$')  # 正则验证手机号
        address: Optional[str] = None  # 可选参数
        sex: GenderEnum  # 枚举验证,只能传: 男和女
        likes: List[str]  # 值会自动转成传字符串列表
        scores: Dict[str, float]  # key会转成字符串,val 会转成浮点型
    • 1

    @注意:上面列举的都是基本使用,实际中可以组合进行多项组合使用,如items: List[constr(min_length=1, max_length=3)] : 限制列表中的每个字符串长度的范围

    2.3 自定义验证

    @validator 装饰器用于定义自定义验证函数,具体是如下:

    from pydantic import BaseModel, constr, conint, validator
    ...
    class PydanticVerifyParam(BaseModel):
        """
        用来学习使用pydantic模型验证
        """

        user_name: str  # 基本类型
        ...
        @validator("user_name")
        def validateUsername(cls, value: str):
            """
            自定义验证函数
            """

            if value.find("傻") > -1:
                raise ValueError("user_name不能包含敏感词")
            return value      
    • 1

    验证结果:

    // 当参数user_name传:你好傻
    {
      "detail": [
        {
          "loc": [
            "body",
            "user_name"
          ],
          "msg""user_name不能包含敏感词",
          "type""value_error"
        }
      ]
    }
    • 1

    2.4 其他验证

    • EmailStr: 用于验证字符串是否是有效的电子邮件地址。
    • IPvAnyAddress: 用于验证字符串是否是有效的 IPv4 或 IPv6 地址。
    • StrictBool: 用于验证字符串是否是严格的布尔值( truefalse)。
    • AnyHttpUrl: 用于验证字符串是否是有效的 URL,包括以 httphttps 开头的 URL

    更多验证方式可查看文档: https://docs.pydantic.dev/latest/concepts/validators/

    本文由 mdnice 多平台发布

  • 相关阅读:
    02:项目二:感应开关盖垃圾桶
    MySQL优化第二篇
    【错误记录】Navigation 导航组件报错 ( Activity xxActivity@3f does not have a NavController set on 2131xx )
    uniapp+vue3+ts+uview-plus搭建项目步骤
    要求设计一款温度采样电路,该电路能够根据被测温度的不同,通过红黄绿三种颜色的指示灯来进行显示。
    leetcode473. 火柴拼正方形
    第四章分类问题
    Ubuntu22.04虚拟机配置双网
    Spring中Bean的作用域
    【FATE联邦学习】FATE框架的大坑,使用6个月有感
  • 原文地址:https://blog.csdn.net/weixin_39001207/article/details/134453288