【问题标题】:How to use values from list as pydantic validator?如何使用列表中的值作为 pydantic 验证器?
【发布时间】:2021-04-04 12:18:58
【问题描述】:

我想创建 pydantic 模型来验证用户表单。 我的模型值之一应该从名称列表中验证。 我成功使用枚举创建模型如下:

from enum import Enum
class Fruit(str, Enum):
    APPLE = 'apple'
    BANANA = 'banana'
    MELON = 'melon'

from pydantic import BaseModel
class UserForm(BaseModel):
    fruit: Fruit
    name: str

现在我想将枚举切换到我的代码中的值列表:

fruit = ['apple','banana','melon']

我怎样才能做到这一点?

tnx

【问题讨论】:

    标签: python list enums fastapi pydantic


    【解决方案1】:

    我提出了一个优雅的解决方案。

    from pydantic import BaseModel
    from typing import List
    from enum import Enum
    
    
    class Fruit(str, Enum):
        APPLE = 'apple'
        BANANA = 'banana'
        MELON = 'melon'
    
    
    class UserForm(BaseModel):
        fruits: List[Fruit]
        name: str
    

    就是这样。

    • 您无需编写自己的验证器
    • 告诉 pydantic 你需要一个 Fruit 对象的列表,它会为你做这件事

    查看上面的代码:

    把上面的代码放到一个文件main.py.

    运行

    python -i main.py
    
    >>> uf = UserForm(fruits=['apple','banana'],name='hello')
    >>> uf
    UserForm(fruits=[<Fruit.APPLE: 'apple'>, <Fruit.BANANA: 'banana'>], name='hello')
    
    
    >>> af = UserForm(fruits=['monkey','apple'],name='hello')
    Traceback (most recent call last):
      File "<stdin>", line 1, in <module>
      File "pydantic/main.py", line 400, in pydantic.main.BaseModel.__init__
    pydantic.error_wrappers.ValidationError: 1 validation error for UserForm
    fruits -> 0
      value is not a valid enumeration member; permitted: 'apple', 'banana', 'melon' (type=type_error.enum; enum_values=[<Fruit.APPLE: 'apple'>, <Fruit.BANANA: 'banana'>, <Fruit.MELON: 'melon'>])
    >>> 
    

    pydantic 会引发错误,因为monkey 不在水果中。

    【讨论】:

      【解决方案2】:

      您也可以通过Literal 类型的列表来执行此操作。像这样:

      import pydantic
      from typing import Literal, List
      
      class M(pydantic.BaseModel):
          fruits: List[Literal["apple", "orange"]]
      
      print(M.parse_obj({"fruits":["apple", "orange"]}))  # OK fruits=['apple', 'orange']
      print(M.parse_obj({"fruits":["apple", "orange", "potato"]}))  # Error unexpected value potato
      

      【讨论】:

        【解决方案3】:

        您可以通过以下方式使用validator

         from pydantic import BaseModel, ValidationError, validator
         class UserForm(BaseModel):
            fruit: str
            name: str
            @validator('fruit')
            def fruit_must_be_in_fruits(cls,fruit):
              fruits=['apple','banana','melon']
              if fruit not in fruits:
                raise ValueError(f'must be in {fruits}')
              return fruit
         try:
            UserForm(fruit="apple",name="apple")
         except ValidationError as e:
            print(e)
        

        如果不符合条件会引发验证错误。

        【讨论】:

        • 嗨,非常感谢。但它仍然无法按我的意愿工作。我在 fastapi 中使用这个 UserForm,这意味着虽然 swagger/docs 会在我使用枚举解决方案时自动为用户建议所有值,但它不会在此解决方案中建议它们。
        【解决方案4】:

        您可以通过其 .__members__ 字典获取有关枚举的信息 - 不过在这里您可以简单地迭代它的键:

        from enum import Enum
        class Fruit(str, Enum):
            APPLE = 'apple'
            BANANA = 'banana'
            MELON = 'melon'
        
        # only need __members__ if you need more infos about it
        
        print(Fruit.__members__)
        
        # you do not need the __members__ if you just want the keys
        print([name.lower() for name in Fruit])
        

        输出:

        # enums __members__ dictionary
        {'APPLE': <Fruit.APPLE: 'apple'>, 
         'BANANA': <Fruit.BANANA: 'banana'>, 
         'MELON': <Fruit.MELON: 'melon'>} 
        
        # lower keys
        ['apple', 'banana', 'melon']
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2022-11-02
          • 2021-08-14
          • 2019-09-04
          • 1970-01-01
          • 2020-07-12
          • 2021-05-24
          • 2022-08-12
          • 2020-08-26
          相关资源
          最近更新 更多