RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 1355548
Accepted
evYpe
evYpe
Asked:2022-04-30 14:58:41 +0000 UTC2022-04-30 14:58:41 +0000 UTC 2022-04-30 14:58:41 +0000 UTC

如何根据字段之一的值进行不同的验证

  • 772

问题如下:

我们有具有以下结构的 JSON:

{
    key1: [
        {
         type_x: str,
         atr1: str,
         atr2: int
        },
        {
         type_x: str,
         atr1: str
        },
        {
         type_x: str,
         atr1: str,
         atr2: int,
         atr3: int
        },
    ],
    key2: [
        {
         atr1: str,
         atr2: int
        }
    ]
}

我需要创建一个用于验证的模型,但是对于键 key1 的字典列表的不同元素,我需要根据 type_x 键的值应用不同的验证。如您所见,列表元素中的参数数量不同,比方说,所需的参数取决于 type_x 参数的值。例如,如果值为type_x = 'base',则其模型为:

class MyBase(BaseClass):
    type_x: str
    atr1: str
    atr2: int

如果值type_x = 'root':

class MyRoot(BaseClass):
    type_x: str
    atr1: str
    atr3: int

我想出了如何为 key1 列表的每个元素编写相同的验证:

class MyClass(BaseClass):
    type_x: str
    atr1: str
    atr2: int

但是如何根据type_x的值做出不同的必填参数呢?当然,理想情况下,这应该在一个通用模型的框架内完成,以免为每个版本的 type_x 值生成单独的模型。谢谢你。

python
  • 2 2 个回答
  • 10 Views

2 个回答

  • Voted
  1. insolor
    2022-04-30T15:33:14Z2022-04-30T15:33:14Z

    要针对多个字段进行验证,请使用root_validator:

    from pydantic import BaseModel, root_validator
    
    
    class MyClass(BaseModel):
        type_x: str
        atr1: str
        atr2: int
        
        @root_validator
        def check_depending_on_type_x(cls, values):
            # values - словарь значений атрибутов,
            # значения получаем по строковому имени атрибутов
            type_x = values.get("type_x")
            
            # Тут пишите ваше условие, в зависимости от которого должны выполняться разные проверки
            if type_x == "something":  
                if values.get("atr1") != "qwerty":  # Меняете на нужную проверку
                    raise ValueError("Ошибка 1")
            else:
                if values.get("atr2") != 42:  # Меняете на вашу проверку (другую)
                    raise ValueError("Ошибка 2")
            
            # Если все хорошо, возвращаем values
            return values
    

    更新。如果 JSON 中可能不存在某个字段,则“包装”其类型Optional(即字面意思是“可选”),缺失的字段将被初始化为None:

    from pydantic import BaseModel
    from typing import Optional
    
    
    class MyRoot(BaseModel):
        type_x: str
        atr1: Optional[str]
        atr2: Optional[int]
        atr3: Optional[int]
    
    
    print(repr(
        MyRoot.parse_obj({"type_x": "123", "atr1": "asdf", "atr2": 1})
    ))
    
    print(repr(
        MyRoot.parse_obj({"type_x": "345", "atr1": "qwer"})
    ))
    
    print(repr(
        MyRoot.parse_obj({"type_x": "789", "atr1": "qwerty", "atr2": 2, "atr3": 3})
    ))
    

    结论:

    MyRoot(type_x='123', atr1='asdf', atr2=1, atr3=None)
    MyRoot(type_x='345', atr1='qwer', atr2=None, atr3=None)
    MyRoot(type_x='789', atr1='qwerty', atr2=2, atr3=3)
    

    最重要的是,您已经可以根据type_x答案的第一部分所示的相同方式根据值来加快对正在填写的字段的验证(如果必须填写该字段,请检查它是否为is not None)。

    如果稍后您需要转换为 JSON,并且希望“空”字段不进入 JSON,请使用参数转换为 json exclude_unset=True:

    my_root = MyRoot.parse_obj({"type_x": "123", "atr1": "asdf", "atr2": 1})
    print(repr(my_root))  # MyRoot(type_x='123', atr1='asdf', atr2=1, atr3=None)
    print(my_root.json())  # {"type_x": "123", "atr1": "asdf", "atr2": 1, "atr3": null}
    print(my_root.json(exclude_unset=True))  # {"type_x": "123", "atr1": "asdf", "atr2": 1}
    
    • 2
  2. Best Answer
    insolor
    2022-06-19T22:10:55Z2022-06-19T22:10:55Z

    通过单独的类实现,具体类型由其中一个字段的值决定。这在 Pydantic 文档中称为区分联合(又名标记联合) 。

    from pydantic import BaseModel, ValidationError, Field, parse_obj_as
    from typing import Literal, Union
    from typing_extensions import Annotated
    
    
    class MyBase(BaseModel):
        type_x: Literal["base"]
        atr1: str
        atr2: int
    
    
    class MyRoot(BaseModel):
        type_x: Literal["root"]
        atr1: str
        atr3: int
    
    
    CommonModel = Annotated[Union[MyBase, MyRoot], Field(discriminator='type_x')]
    
    
    examples = [
        {"type_x": "base", "atr1": "asdf", "atr2": 1},  # Корректная модель base
        {"type_x": "root", "atr1": "asdf", "atr3": 1},  # Корректная модель root
        {"type_x": "foobar"},  # Неизвестный тип
        {"type_x": "base", "atr1": "qwer"},  # Отсутствует одно поле для типа base
        {"type_x": "root"},  # Отсутствуют два поле для типа root
    ]
    
    
    for example in examples:
        print(example)
        try:
            print(repr(
                parse_obj_as(CommonModel, example)
            ))
        except ValidationError as ex:
            print(ex)
        print()
    

    结论:

    {'type_x': 'base', 'atr1': 'asdf', 'atr2': 1}
    MyBase(type_x='base', atr1='asdf', atr2=1)
    
    {'type_x': 'root', 'atr1': 'asdf', 'atr3': 1}
    MyRoot(type_x='root', atr1='asdf', atr3=1)
    
    {'type_x': 'foobar'}
    1 validation error for ParsingModel[typing_extensions.Annotated[Union[__main__.MyBase, __main__.MyRoot], FieldInfo(default=PydanticUndefined, discriminator='type_x', extra={})]]
    __root__
      No match for discriminator 'type_x' and value 'foobar' (allowed values: 'base', 'root') (type=value_error.discriminated_union.invalid_discriminator; discriminator_key=type_x; discriminator_value=foobar; allowed_values='base', 'root')
    
    {'type_x': 'base', 'atr1': 'qwer'}
    1 validation error for ParsingModel[typing_extensions.Annotated[Union[__main__.MyBase, __main__.MyRoot], FieldInfo(default=PydanticUndefined, discriminator='type_x', extra={})]]
    __root__ -> MyBase -> atr2
      field required (type=value_error.missing)
    
    {'type_x': 'root'}
    2 validation errors for ParsingModel[typing_extensions.Annotated[Union[__main__.MyBase, __main__.MyRoot], FieldInfo(default=PydanticUndefined, discriminator='type_x', extra={})]]
    __root__ -> MyRoot -> atr1
      field required (type=value_error.missing)
    __root__ -> MyRoot -> atr3
      field required (type=value_error.missing)
    
    • 1

相关问题

  • 是否可以以某种方式自定义 QTabWidget?

  • telebot.anihelper.ApiException 错误

  • Python。检查一个数字是否是 3 的幂。输出 无

  • 解析多个响应

  • 交换两个数组的元素,以便它们的新内容也反转

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    表格填充不起作用

    • 2 个回答
  • Marko Smith

    提示 50/50,有两个,其中一个是正确的

    • 1 个回答
  • Marko Smith

    在 PyQt5 中停止进程

    • 1 个回答
  • Marko Smith

    我的脚本不工作

    • 1 个回答
  • Marko Smith

    在文本文件中写入和读取列表

    • 2 个回答
  • Marko Smith

    如何像屏幕截图中那样并排排列这些块?

    • 1 个回答
  • Marko Smith

    确定文本文件中每一行的字符数

    • 2 个回答
  • Marko Smith

    将接口对象传递给 JAVA 构造函数

    • 1 个回答
  • Marko Smith

    正确更新数据库中的数据

    • 1 个回答
  • Marko Smith

    Python解析不是css

    • 1 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5