嵌套的 JSON 可以简单地由嵌套的 Pydantic 模型表示。每个对象都可以映射到一个模型,并且该模型可以具有其他 Pydantic 模型或 Pydantic 模型列表的属性。
你从最里面的对象开始:
{
"name2": "demo1",
"nameid": "2",
}
可以表示为:
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'
如果其中一个值错误,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]+)
然后你向上移动到每个Column 的父对象:
{
"name1": "abc",
"surname": "asd",
"columns": [
{"name2": "demo1", "nameid": "2"},
],
}
然后可以表示为:
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
我们重用之前的Column 类定义,即columns 属性是Column 的列表。 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'
同样,如果任何值是错误的(无论是来自外部属性还是来自最内部的属性),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)
然后,您再次向上移动到每个Demo 的父对象
{
"name": "suzuki",
"colors": "deq",
"demo": [
{
"name1": "abc",
"surname": "asd",
"columns": [
{"name2": "demo1", "nameid": "2"},
],
}
],
}
可以表示为
from pydantic import BaseModel, conlist
class Car(BaseModel):
name: str
colors: str
demo: conlist(Demo, min_items=1)
与我们对Column 所做的相同,我们有一个demo 属性,它被建模为Demo 对象的列表。 Pydantic 可以处理 demo 的嵌套初始化和验证,其中包括其内部 Column 类。
最后,你会到达最上面的物体:
test1 = {
"abx": [
{...},
{...},
]
}
它有一个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')])
您还可以在任何地方停止建模,例如,停止建模 Car 并从原始 abx 对象进行验证:
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')])])
同样,如果您有错误,即使在内部 Column 模型的某个地方,您也会收到验证错误。
这样做的好处是您可以依次测试和验证每个对象,从最里面的对象一直到最外面的对象。有关constr 和conlist 用法的更多详细信息,请查看Constrained Types 的Pydantic 文档以及其他Field Types 和Validators 以获得更复杂的验证。