我将 pydanticBaseModel与这样的验证器一起使用:
from datetime import date
from typing import List, Optional
from pydantic import BaseModel, BaseConfig, validator
class Model(BaseModel):
class Config(BaseConfig):
allow_population_by_alias = True
fields = {
"some_date": {
"alias": "some_list"
}
}
some_date: Optional[date]
some_list: List[date]
@validator("some_date", pre=True, always=True)
def validate_date(cls, value):
if len(value) < 2: # here value is some_list
return None
return value[0] # return the first value - let's assume it's a date string
# This reproduces the problem
m = Model(some_list=['2019-01-03'])
Run Code Online (Sandbox Code Playgroud)
我想some_date根据 的值计算 的值,some_list并在None满足某个条件时进行计算。
我的 JSON 从不包含该字段some_date,它总是基于some_list因此填充pre=True, always=True。但是,默认验证器some_date将在我的自定义验证器之后运行,如果validate_date返回None.
有没有办法创建这样一个字段,它只能由另一个人计算并且仍然可以Optional?
Y0d*_*0da 10
如果您希望能够根据另一个字段动态修改一个字段,则可以使用该values参数。它包含所有以前的字段,并且要注意:顺序很重要。您可以使用 avalidator或 a来执行此操作root_validator。
validator>>> from datetime import date
>>> from typing import List, Optional
>>> from pydantic import BaseModel, validator
>>> class Model(BaseModel):
some_list: List[date]
some_date: Optional[date]
@validator("some_date", always=True)
def validate_date(cls, value, values):
if len(values["some_list"]) < 2:
return None
return values["some_list"][0]
>>> Model(some_list=['2019-01-03', '2020-01-03', '2021-01-03'])
Model(some_list=[datetime.date(2019, 1, 3), datetime.date(2020, 1, 3), datetime.date(2021, 1, 3)],
some_date=datetime.date(2019, 1, 3))
Run Code Online (Sandbox Code Playgroud)
但是正如我所说,如果您交换some_listand的顺序some_date,您将拥有KeyError: 'some_list'!
root_validator另一种选择是使用root_validator. 这些作用于所有领域:
>>> class Model(BaseModel):
some_list: List[date]
some_date: Optional[date]
@root_validator
def validate_date(cls, values):
if not len(values["some_list"]) < 2:
values["some_date"] = values["some_list"][0]
return values
>>> Model(some_list=['2019-01-03', '2020-01-03', '2021-01-03'])
Model(some_list=[datetime.date(2019, 1, 3), datetime.date(2020, 1, 3), datetime.date(2021, 1, 3)],
some_date=datetime.date(2019, 1, 3))
Run Code Online (Sandbox Code Playgroud)
更新:正如其他人指出的那样,现在可以使用较新的版本(> = 0.20)来完成此操作。看到这个答案。(旁注:即使OP的代码现在也可以工作,但是没有别名就更好了。)
从略读文档和 pydantic 的来源来看,我倾向于说 pydantic 的验证机制目前对验证函数中的类型转换( list -> date、 )支持非常有限。list -> NoneType
然而,退一步来说,您使用aliasand 标志的方法allow_population_by_alias似乎有点过载。some_date仅需要作为 的快捷方式some_list[0] if len(some_list) >= 2 else None,但它永远不会独立于 进行设置some_list。如果确实如此,为什么不选择以下选项呢?
class Model(BaseModel):
some_list: List[date] = ...
@property
def some_date(self):
return None if len(self.some_list) < 2 else self.some_list[0]
Run Code Online (Sandbox Code Playgroud)