如何在 pydantic 中听写或数据检查密钥

How to dict or data check keys in pydantic

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必须丢弃

您所说的“丢弃”数据并不完全清楚。

您当前的实施应该引发 ValidationError 因为 data2 中的 mails 中的第二项缺少 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)