jon*_*box 29 python python-3.x pydantic
如何更改 pydantic 中的日期格式以进行验证和序列化?为了验证我正在使用@validator. 这两种情况都有解决办法吗?
小智 28
您可以使用pydantic 的自定义 json 编码器来实现自定义 json序列化器。然后,与pydantic 的自定义验证器一起,您就可以拥有这两种功能。
from datetime import datetime, timezone
from pydantic import BaseModel, validator
def convert_datetime_to_iso_8601_with_z_suffix(dt: datetime) -> str:
return dt.strftime('%Y-%m-%dT%H:%M:%SZ')
def transform_to_utc_datetime(dt: datetime) -> datetime:
return dt.astimezone(tz=timezone.utc)
class DateTimeSpecial(BaseModel):
datetime_in_utc_with_z_suffix: datetime
# custom input conversion for that field
_normalize_datetimes = validator(
"datetime_in_utc_with_z_suffix",
allow_reuse=True)(transform_to_utc_datetime)
class Config:
json_encoders = {
# custom output conversion for datetime
datetime: convert_datetime_to_iso_8601_with_z_suffix
}
if __name__ == "__main__":
special_datetime = DateTimeSpecial(datetime_in_utc_with_z_suffix="2042-3-15T12:45+01:00") # note the different timezone
# input conversion
print(special_datetime.datetime_in_utc_with_z_suffix) # 2042-03-15 11:45:00+00:00
# output conversion
print(special_datetime.json()) # {"datetime_in_utc_with_z_suffix": "2042-03-15T11:45:00Z"}
Run Code Online (Sandbox Code Playgroud)
这个变体也适用于 fastapi 的序列化器,我实际上就是以这种方式使用它的。
Ome*_*ham 19
我认为预验证器可以在这里提供帮助。
from datetime import datetime, date
from pydantic import BaseModel, validator
class OddDate(BaseModel):
birthdate: date
@validator("birthdate", pre=True)
def parse_birthdate(cls, value):
return datetime.strptime(
value,
"%d/%m/%Y"
).date()
if __name__ == "__main__":
odd_date = OddDate(birthdate="12/04/1992")
print(odd_date.json()) #{"birthdate": "1992-04-12"}
Run Code Online (Sandbox Code Playgroud)
aig*_*fer 16
如果您不一定希望将此行为应用于所有日期时间,您可以创建一个扩展的自定义类型datetime。例如,要创建一个始终确保我们将 tzinfo 设置为 UTC 的日期时间的自定义类型:
from datetime import datetime, timezone
from pydantic.datetime_parse import parse_datetime
class utc_datetime(datetime):
@classmethod
def __get_validators__(cls):
yield parse_datetime # default pydantic behavior
yield cls.ensure_tzinfo
@classmethod
def ensure_tzinfo(cls, v):
# if TZ isn't provided, we assume UTC, but you can do w/e you need
if v.tzinfo is None:
return v.replace(tzinfo=timezone.utc)
# else we convert to utc
return v.astimezone(timezone.utc)
@staticmethod
def to_str(dt:datetime) -> str:
return dt.isoformat() # replace with w/e format you want
Run Code Online (Sandbox Code Playgroud)
那么你的 pydantic 模型将如下所示:
from pydantic import BaseModel
class SomeObject(BaseModel):
some_datetime_in_utc: utc_datetime
class Config:
json_encoders = {
utc_datetime: utc_datetime.to_str
}
Run Code Online (Sandbox Code Playgroud)
走这条路线有助于可重用性和关注点分离:)
Tra*_*umi 11
从 pydantic 2.0 开始,我们可以使用@field_serializer装饰器进行序列化和@field_validator验证。
摘自pydantic 文档:
from datetime import datetime, timezone
from pydantic import BaseModel, field_serializer
class WithCustomEncoders(BaseModel):
dt: datetime
@field_serializer('dt')
def serialize_dt(self, dt: datetime, _info):
return dt.timestamp()
m = WithCustomEncoders(
dt=datetime(2032, 6, 1, tzinfo=timezone.utc)
)
print(m.model_dump_json())
#> {"dt":1969660800.0}
Run Code Online (Sandbox Code Playgroud)
并进行验证:
from pydantic_core.core_schema import FieldValidationInfo
from pydantic import BaseModel, ValidationError, field_validator
class UserModel(BaseModel):
name: str
username: str
password1: str
password2: str
@field_validator('name')
def name_must_contain_space(cls, v):
if ' ' not in v:
raise ValueError('must contain a space')
return v.title()
@field_validator('password2')
def passwords_match(cls, v, info: FieldValidationInfo):
if 'password1' in info.data and v != info.data['password1']:
raise ValueError('passwords do not match')
return v
@field_validator('username')
def username_alphanumeric(cls, v):
assert v.isalnum(), 'must be alphanumeric'
return v
user = UserModel(
name='samuel colvin',
username='scolvin',
password1='zxcvbn',
password2='zxcvbn',
)
print(user)
"""
name='Samuel Colvin' username='scolvin' password1='zxcvbn' password2='zxcvbn'
"""
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
72683 次 |
| 最近记录: |