如何在pydantic中记录或检查密钥

2024-06-28 20:49:48 发布

您现在位置:Python中文网/ 问答频道 /正文

class mail(BaseModel):
    mailid: int
    email: str
    
class User(BaseModel):
    id: int
    name: str
    mails: List[mail]

data1 = {
    'id': 123,
    'name': 'Jane Doe',
    'mails':[
        {'mailid':1,'email':'aeajhs@gmail.com'}, 
        {'mailid':2,'email':'aeajhsds@gmail.com'}
    ]
}
userobj = User(**data1)  # Accepted
data2 = {
        'id': 123,
        'name': 'Jane Doe',
        'mails':[
            {'mailid':1,'email':'aeajhs@gmail.com'}, 
            {'email':'aeajhsds@gmail.com'}
        ]
    }
    
userobj = User(**data2)  # Discarded or not accepted

我想检查传递给pydantic模型的字典中的键,因此如果给定字典中不存在键,我想丢弃该数据。 例如,在邮件中的data2中{'email':'aeajhsds@gmail.com'}必须丢弃data2


Tags: namecomidemailmailgmailclassbasemodel
3条回答

现在还不清楚“丢弃”数据是什么意思

当前实现应引发ValidationError,因为data2mails的第二项中缺少mailid

Traceback (most recent call last):
...
pydantic.error_wrappers.ValidationError: 1 validation error for User
mails -> 1 -> mailid
  field required (type=value_error.missing)

如果您的意图是简单地忽略data2(或者通常是无效输入),我建议将所有内容包装在try-except块中,例如:

from pydantic import ValidationError

# your code here

try:
    userobj = User(**data2)
except ValidationError as exc:
    # Optional printout or logging:
    print(f"Encountered the following error when parsing `{data2}`:\n{exc}.\nSkipping...")

程序现在将显示以下消息:

Encountered the following error when parsing `{'id': 123, 'name': 'Jane Doe', 'mails': [{'mailid': 1, 'email': 'aeajhs@gmail.com'}, {'email': 'aeajhsds@gmail.com'}]}`:
1 validation error for User
mails -> 1 -> mailid
  field required (type=value_error.missing).
Skipping...

另类

另一方面,如果您想忽略mailid缺失的事实,可以在模型定义中设置Optional,例如:

from typing import Optional

class mail(BaseModel):
    mailid: Optional[int]
    email: str

# ... everything stays the same

# This works now:
userobj = User(**data2)

print(userobj)
# id=123 name='Jane Doe' mails=[mail(mailid=1, email='aeajhs@gmail.com'), mail(mailid=None, email='aeajhsds@gmail.com')]

你可以使用@juanpa arrivillaga所说的pydantic.validator

这里有几个小技巧:

  • Optional验证结束时,它可能为空
  • pre=True是否应在标准验证器之前调用此验证器(否则在之后)
from pydantic import BaseModel, validator
from typing import List, Optional


class Mail(BaseModel):
    mailid: int
    email: str
    
class User(BaseModel):
    id: int
    name: str
    mails: Optional[List[Mail]]

    @validator('mails', pre=True)
    def mail_check(cls, v):
        mail_att = [i for i in Mail.__fields__.keys()]
        mail_att_count = 0
        for i, x in enumerate(v):
            for k in dict(x).keys():
                if k in mail_att:
                    mail_att_count += 1
            if mail_att_count != len(mail_att):
                v.pop(i)
            mail_att_count = 0
        return v
data = {
    'id': 123,
    'name': 'Jane Doe',
    'mails':[
        {'mailid':1,'email':'aaa@gmail.com'},
        {'mailid':2,'email':'bbb@gmail.com'},
        {'email':'ccc@gmail.com'}
    ]
}

x = User(**data)  # Discarded or not accepted
print(x.id)
print(x.name)
print(x.mails)

# Output
# >>123
# >>Jane Doe
# >>[Mail(mailid=1, email='aaa@gmail.com'), Mail(mailid=2, email='bbb@gmail.com')]

您可以在预验证中迭代mails列表,并执行一个简单的try-子句来检查每个mail项是否正确:

from pydantic import BaseModel, validator
from pydantic.error_wrappers import ValidationError
from typing import List

class mail(BaseModel):
    mailid: int
    email: str

class User(BaseModel):
    id: int
    name: str
    mails: List[mail]

    @validator("mails", pre=True)
    def must_be_valid_mail(cls, v):
        ret = []
        for item in list(v):
            try:
                mail(**item)
                ret.append(item)
            except ValidationError as er:
                print(er)
        return ret

data = {
    'id': 123,
    'name': 'Jane Doe',
    'mails':[
        {'mailid':1,'email':'aeajhs@gmail.com'}, 
        {'email':'aeajhsds@gmail.com'}
    ]
}

userobj = User(**data)
print(userobj)

相关问题 更多 >