代码之家  ›  专栏  ›  技术社区  ›  Amin Ba

如何在fastapi请求验证中进行不区分大小写的选择

  •  0
  • Amin Ba  · 技术社区  · 2 年前

    我有这个申请:

    import enum
    from typing import Annotated, Literal
    
    import uvicorn
    from fastapi import FastAPI, Query, Depends
    from pydantic import BaseModel
    
    app = FastAPI()
    
    
    class MyEnum(enum.Enum):
        ab = "ab"
        cd = "cd"
    
    
    class MyInput(BaseModel):
        q: Annotated[MyEnum, Query(...)]
    
    
    @app.get("/")
    def test(inp: MyInput = Depends()):
        return "Hello world"
    
    
    def main():
        uvicorn.run("run:app", host="0.0.0.0", reload=True, port=8001)
    
    
    if __name__ == "__main__":
        main()
    

    curl http://127.0.0.1:8001/?q=ab curl http://127.0.0.1:8001/?q=cd return“Hello World”

    但是这些

    • curl http://127.0.0.1:8001/?q=aB
    • curl http://127.0.0.1:8001/?q=AB
    • curl http://127.0.0.1:8001/?q=Cd

    退货 422Unprocessable Entity 这是有道理的。

    如何使此验证用例不敏感?

    0 回复  |  直到 2 年前
        1
  •  6
  •   Chris Brian    2 年前

    你可以 enum 通过重写 Enum _missing_ 方法根据文件 类方法 默认情况下不执行任何操作,可以用来查找中找不到的值 cls ;因此,允许尝试通过 value

    请注意,可以从 str 类(例如。, class MyEnum(str, Enum) ),这将指示枚举中的所有成员必须具有指定类型的值(例如。, str )。这还允许将字符串与枚举成员进行比较(使用相等运算符 == ),而无需使用 价值 枚举成员上的属性(例如。, if member.lower() == value )。否则,如果枚举类声明为 class MyEnum(Enum) (没有 str 子类),则需要使用 价值 枚举成员上的属性(例如。, if member.value.lower() == value )以安全地将枚举成员与字符串进行比较。

    此外,请注意,调用 lower() 除非类的枚举值也包括大写字母(或大小写的组合),否则枚举成员上的函数是不必要的。因此,对于下面只使用小写字母的示例,您可以避免使用它,而只使用 if member == value 将所述枚举成员与值进行比较;因此,避免了您拨打 下部() 类中每个成员的函数。

    实例

    from enum import Enum
    
    class MyEnum(str, Enum):
        ab = 'ab'
        cd = 'cd'
        
        @classmethod
        def _missing_(cls, value):
            value = value.lower()
            for member in cls:
                if member.lower() == value:
                    return member
            return None
    

    示例(在Python 3.11+中)

    在里面 Python 3.11+ ,可以使用新引入的 StrEnum ,允许使用 auto() 特性,从而将成员名称的小写版本作为值。

    from enum import StrEnum, auto
    
    class MyEnum(StrEnum):    
        AB = auto()
        CD = auto()
        
        @classmethod
        def _missing_(cls, value):
            value = value.lower()
            for member in cls:
                if member == value:
                    return member
            return None
    
        2
  •  0
  •   Hunter_71    1 年前

    我真的很喜欢公认答案的建议,但它可以稍微简化(和概括):

    class CaseInsensitiveEnum(str, Enum):
        @classmethod
        def _missing_(cls, value: str):
            for member in cls:
                if member.lower() == value.lower():
                    return member
            return None
    
    
    class MyEnum(CaseInsensitiveEnum):
        ab = 'ab'
        cd = 'cd'
    

    正如前面的评论中所建议的,它可以通过两种方式进行优化:

    • member.lower() 如果所有枚举值都将指定为小写,则不需要
    • value.lower() 可以在for循环之外执行一次