Python [Pydantic] -基于类中其他对象的默认值



我想在没有提供电子邮件的情况下设置默认电子邮件,即:

name = a 
last_name = b
email = None 

email将变成"a_b@email.com">

我尝试了类似的东西,但显然没有工作作为名称,last_name函数中没有定义

class User(BaseModel):
name: Optional[str] = ''
last_name: Optional[str] = ''
email: EmailStr

@validator('email')
def set_email(cls, email):
if not email:
return name + last_name + '@email.com' 
else:
return email

更新-仍然不工作,我试着:

@root_validator(pre=True)
def email_set_config(cls, values):
email, name ,last_name = values.get('email'), values.get('name') , values.get('last_name')
if email is None :
email= name + '_' + name + '@' + last_name 
return values

解决方案:

添加到类:

——更新

  • 实际上它工作没有定义类配置:
class Config:
validate_assignment = True
@validator('email')
def set_email(cls, v, values, **kwargs):
return email or values["name"] + '_' + values["name"] + '@' + ["last_name"]

声誉不高,不能评论,所以我就在这里展开@NobbyNobbs的回答^^

对于使用pydantic.validator的最后一个示例,您可以使用alwayskwargs来始终运行验证器,即使没有提供该值。

文档中的链接:https://pydantic-docs.helpmanual.io/usage/validators/#validate-always

所以你的例子是:

from typing import Optional
import pydantic

class User(pydantic.BaseModel):
first_name: str
last_name: str
email: Optional[pydantic.EmailStr]
@pydantic.validator('email', always=True)
def set_email(cls, v, values, **kwargs):    
return v or values["first_name"] + '_' + values["last_name"] + '@email.com'

if __name__ == "__main__":
print(User(first_name="jon", last_name="doe"))  # first_name='jon' last_name='doe' email='jon_doe@email.com'
print(User(first_name="jon", last_name="doe", email=None))  # first_name='jon' last_name='doe' email='jon_doe@email.com'

我稍微改变了你的模型,现在它有两个必填字段和一个可选字段,它从其他两个计算。

from typing import Optional
import pydantic

class User(pydantic.BaseModel):
first_name: str
last_name: str
email: Optional[pydantic.EmailStr]
在实例创建期间验证数据的第一种方法,同时具有完整的模型上下文,是使用@pydantic.root_validator:
@pydantic.root_validator
def email_set_config(cls, values):
email, name, last_name = values.get('email'), values.get('first_name'), values.get('last_name')
if email is None:
values["email"] = name + '_' + last_name + '@email.com'
return values

if __name__ == "__main__":
u = User(first_name="jon", last_name="doe")
print(u)  # first_name='jon' last_name='doe' email='jon_doe@email.com'

但是如果你只想控制实例化过程,我建议你只是在你的模型中覆盖__init__,像这样

def __init__(__pydantic_self__, **data: Any) -> None:
email, name, last_name = data.get('email'), data.get('first_name'), data.get('last_name')
if email is None:
data["email"] = name + '_' + last_name + '@email.com'
super().__init__(**data)

在我看来,与验证器相比,这是一种更简单直观的方法,我更喜欢它。

您提到的非根验证器的可能解决方案对我来说有一些棘手和一些意想不到的行为。

如果将命名的email参数传递给构造函数,它会像预期的那样工作,但如果不传递则不会。

@pydantic.validator('email')
def set_email(cls, v, values, **kwargs):
return v or values["first_name"] + '_' + values["last_name"] + '@email.com'

if __name__ == "__main__":
print(User(first_name="jon", last_name="doe"))  # first_name='jon' last_name='doe' email=None
print(User(first_name="jon", last_name="doe", email=None))  # first_name='jon' last_name='doe' email='jon_doe@email.com'

在我的案例中,解决方案是:

@pydantic.root_validator(pre=True)
def method_before_validation(cls, data):

我在一个复杂对象的根类中使用它。我有类似的对象与订单和单独的对象与客户端,我需要把客户端的id到每个订单的对象。因此,我们可以在实际验证之前对数据结构,类型等进行数据修改。

Pydantic自v1.5以来已经添加了default_factory,您可以使用下面的代码来拥有默认的EmailStr值,以及其他子模型类对象

class User(BaseModel):
name: Optional[str] = ''
last_name: Optional[str] = ''
email: EmailStr = Field(
default_factory=lambda: EmailStr('foo@example.org'))