简体   繁体   English

如何在 python 中使用 Pydantic model 验证 2 个嵌套的 json?

[英]How to validate 2 nested json using Pydantic model in python?

test1 = {
  "abx": [
    {
      "name": "toyota",
      "colors": "abc",
      "demo": [
        {
          "name1": "pqr",
          "surname": "abc",
          "columns": [
            {
              "name2": "demo",
              "nameid": "1"
            }
          ]
        }
      ]
    },
    {
      "name": "suzuki",
      "colors": "deq",
      "demo": [
        {
          "name1": "abc",
          "surname": "asd",
          "columns": [
            {
              "name2": "demo1",
              "nameid": "2"
            }
          ]
        }
      ]
    }
  ]
}

I have 2 nested JSON and both responses have shuffle values.我有 2 个嵌套的 JSON 并且两个响应都有随机播放值。 I wanted to match using Pydantic models for testing in Python.我想匹配使用 Pydantic 模型在 Python 中进行测试。

Is there any way to compare, validate both responses?有什么方法可以比较、验证两个响应吗?

A nested JSON can simply be represented by nested Pydantic models .嵌套的 JSON 可以简单地用嵌套的 Pydantic 模型表示 Each object can be mapped to a model, and that model can have attributes that are other Pydantic models or a list of Pydantic models.每个 object 都可以映射到 model,并且 model 可以具有其他 Pydantic 模型或 Pydantic 模型列表的属性。

You start with the innermost objects:你从最里面的对象开始:

{
    "name2": "demo1",
    "nameid": "2",
}

which can be represented as:可以表示为:

from pydantic import BaseModel, constr

class Column(BaseModel):
    name2: str
    nameid: constr(regex="[0-9]+")  # See: https://pydantic-docs.helpmanual.io/usage/types/#arguments-to-constr
In [2]: raw = {"name2": "demo1", "nameid": "2"}
In [3]: col = Column(**raw)
In [4]: col.name2
Out[4]: 'demo1'
In [5]: col.nameid
Out[5]: '2'

If one of the values is wrong, Pydantic would raise a validation error:如果其中一个值错误,Pydantic 将引发验证错误:

In [6]: raw = {"name2": 1, "nameid": True}
In [7]: col = Column(**raw)
...
ValidationError: 1 validation error for Column
nameid
  string does not match regex "[0-9]+" (type=value_error.str.regex; pattern=[0-9]+)

Then you move up to each Column 's parent object:然后向上移动到每个Column的父 object:

{
    "name1": "abc",
    "surname": "asd",
    "columns": [
        {"name2": "demo1", "nameid": "2"},
    ],
}

which can then be represented as:然后可以表示为:

from pydantic import BaseModel, conlist

class Demo(BaseModel):
    name1: str
    surname: str
    columns: conlist(Column, min_items=1)  # See: https://pydantic-docs.helpmanual.io/usage/types/#arguments-to-conlist

where we reuse the previous Column class definition, to say that the columns attribute is a list of Column 's.我们重用了前面的Column class 定义,也就是说columns属性是Column的列表。 Pydantic can instantiate and validate each attribute of Column under Demo : Pydantic 可以在Demo下实例化和验证Column的每个属性:

In [8]: raw
Out[8]: {'name1': 'abc', 'surname': 'asd', 'columns': [{'name2': 'demo1', 'nameid': '2'}]}
In [9]: demo = Demo(**raw)
In [11]: demo.name1
Out[11]: 'abc'
In [13]: demo.surname
Out[13]: 'asd'
In [14]: demo.columns
Out[14]: [Column(name2='demo1', nameid='2')]
In [15]: demo.columns[0].name2
Out[15]: 'demo1'
In [16]: demo.columns[0].nameid
Out[16]: '2'

Again, if any of the values are wrong (whether from the outer attributes or from the innermost attributes), Pydantic will raise a validation error:同样,如果任何值是错误的(无论是来自外部属性还是来自最内部的属性),Pydantic 将引发验证错误:

In [20]: raw
Out[20]: {'name1': 'abc', 'surname': None, 'columns': [{'name2': 'demo1', 'nameid': '2'}]}
In [21]: demo = Demo(**raw)
...
ValidationError: 1 validation error for Demo
surname
  none is not an allowed value (type=type_error.none.not_allowed)
In [27]: raw
Out[27]: {'name1': 'abc', 'surname': 'asd', 'columns': [{'name2': None, 'nameid': '2'}]}
In [28]: demo = Demo(**raw)
...
ValidationError: 1 validation error for Demo
columns -> 0 -> name2
  none is not an allowed value (type=type_error.none.not_allowed)

Then after that, you move up again to each Demo 's parent object然后,您再次向上移动到每个Demo的父 object

{
    "name": "suzuki",
    "colors": "deq",
    "demo": [
        {
            "name1": "abc",
            "surname": "asd",
            "columns": [
                {"name2": "demo1", "nameid": "2"},
            ],
        }
    ],
}

which can be represented as可以表示为

from pydantic import BaseModel, conlist

class Car(BaseModel):
    name: str
    colors: str
    demo: conlist(Demo, min_items=1)

where, same as what we did for Column , we have a demo attribute that is modeled as a list of Demo objects.其中,与我们为Column所做的一样,我们有一个demo属性,它被建模为Demo对象列表。 Pydantic can handle nested initialization and validation of demo which includes its inner Column class. Pydantic 可以处理demo的嵌套初始化和验证,其中包括其内部Column class。

Finally, you'll reach the uppermost object:最后,您将到达最上面的 object:

test1 = {
    "abx": [
        {...},
        {...},
    ]
}

which has an abx attribute that's a list of Car objects它有一个abx属性,它是Car对象的列表

from pydantic import BaseModel, conlist

class Test(BaseModel):
    abx: conlist(Car, min_items=1)
In [3]: obj = Test(**test1)
In [4]: obj
Out[4]: Test(abx=[Car(name='toyota', colors='abc', demo=[Demo(name1='pqr', surname='abc', columns=[Column(name2='demo', nameid='1')])]), Car(name='suzuki', colors='deq', demo=[Demo(name1='abc', surname='asd', columns=[Column(name2='demo1', nameid='2')])])])

In [5]: obj.abx[1]
Out[5]: Car(name='suzuki', colors='deq', demo=[Demo(name1='abc', surname='asd', columns=[Column(name2='demo1', nameid='2')])])

In [6]: obj.abx[1].demo[0]
Out[6]: Demo(name1='abc', surname='asd', columns=[Column(name2='demo1', nameid='2')])

You can also stop modeling anywhere, for example, stop at modeling a Car and validate from the raw abx object:您还可以在任何地方停止建模,例如,停止建模Car并从原始abx object 进行验证:

In [15]: car1 = Car(**test1['abx'][0])
In [16]: car1
Out[16]: Car(name='toyota', colors='abc', demo=[Demo(name1='pqr', surname='abc', columns=[Column(name2='demo', nameid='1')])])

In [17]: car2 = Car(**test1['abx'][1])
In [18]: car2
Out[18]: Car(name='suzuki', colors='deq', demo=[Demo(name1='abc', surname='asd', columns=[Column(name2='demo1', nameid='2')])])

Again, if you have an error, even somewhere in the inner Column model, you'll get a validation error.同样,如果您有错误,即使在内部Column model 的某个地方,您也会收到验证错误。

The good thing about this is that you can test and validate each object in turn, from the innermost ones up to the outermost one.这样做的好处是您可以从最里面到最外面依次测试和验证每个 object。 For more details about the usage of constr and conlist , check Pydantic docs for Constrained Types as well as the other Field Types and Validators for more complex validations.有关conlist constr的更多详细信息,请查看 Pydantic 文档中的约束类型以及其他字段类型验证器以获取更复杂的验证。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM