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

Avi*_*viC 6 python pydantic

我想设置默认电子邮件以防未提供电子邮件,即:

name = a 
last_name = b
email = None 
Run Code Online (Sandbox Code Playgroud)

电子邮件将变为“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
Run Code Online (Sandbox Code Playgroud)

更新-仍然不起作用,我尝试过:

    @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

Run Code Online (Sandbox Code Playgroud)

解决方案:

添加到类:

- 更新

  • 实际上它可以在没有定义类 Config 的情况下工作:
    class Config:
        validate_assignment = True
Run Code Online (Sandbox Code Playgroud)
    @validator('email')
    def set_email(cls, v, values, **kwargs):
        return email or values["name"] + '_' + values["name"] + '@' + ["last_name"]

Run Code Online (Sandbox Code Playgroud)

obe*_*idi 5

没有足够的声誉来发表评论,所以我将在这里扩展@NobbyNobbs 的答案^^

对于使用 的最后一个示例pydantic.validatoralways即使未提供值,您也可以使用 kwargs 始终运行验证器。

文档中的链接: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'
Run Code Online (Sandbox Code Playgroud)


Nob*_*bbs 3

我对您的模型进行了一些更改,现在它有两个必填字段和一个可选字段,这是根据其他两个字段计算得出的。

from typing import Optional

import pydantic


class User(pydantic.BaseModel):
    first_name: str
    last_name: str
    email: Optional[pydantic.EmailStr]
Run Code Online (Sandbox Code Playgroud)

在实例创建期间验证数据并同时拥有完整模型上下文的第一种方法是使用@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'
Run Code Online (Sandbox Code Playgroud)

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

    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)
Run Code Online (Sandbox Code Playgroud)

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

您在问题中提到的非根验证器的可能解决方案对我来说有棘手且有点意外的行为。

如果您将命名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'
Run Code Online (Sandbox Code Playgroud)