我为日期时间创建了一个 Pydantic 模型,它将处理解析一个类似于
{ "date": "2021-07-01", "time": "12:36:23" }
的 JSON 对象
datetime(2021, 7, 1, 12, 36, 23)
它还为模型生成正确的 JSON 架构。
class TimestampWithSplit(RootModel):
root: datetime
@classmethod
def __get_pydantic_core_schema__(
cls, source: Type[Any], handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
return core_schema.chain_schema(
[
core_schema.typed_dict_schema(
{
"date": core_schema.typed_dict_field(core_schema.date_schema()),
"time": core_schema.typed_dict_field(core_schema.time_schema()),
}
),
core_schema.no_info_plain_validator_function(cls.validate_to_datetime),
]
)
@staticmethod
def validate_to_datetime(value: dict) -> datetime:
return datetime.combine(value["date"], value["time"])
我现在尝试做两件事:
-
我现在想向生成的 json 架构添加描述。目前
TimestampWithSplit.model_json_schema()
返回
{'properties': {'date': {'format': 'date', 'title': 'Date', 'type': 'string'},
'time': {'format': 'time', 'title': 'Time', 'type': 'string'}},
'required': ['date', 'time'],
'type': 'object'}
并且我想添加
{'properties': {'date': {'format': 'date', 'title': 'Date', 'type': 'string', 'description': 'ISO format date, blah blah'},
'time': {'format': 'time', 'title': 'Time', 'type': 'string', 'description': 'ISO format time, blah blah'}},
'required': ['date', 'time'],
'type': 'object'}
- 为日期字段添加自定义验证器,以便它可以解析个位数的日期和月份数字。我通常会这样做:
def validator(value: str):
try:
return datetime.strptime(value, "%Y-%m-%d").date()
except ValueError:
return None
并将该验证器添加为字段上的普通验证器。但我不确定如何将其融入到我所拥有的内容中。
我是否走错了路?如何拥有一个模型,该模型将日期和时间作为单独的字段,但返回
datetime
from
model_validate_json
,同时还自定义 JSON 架构和日期验证?
对 Pydantic 模型的使用方式和想要实现的目标方面做得很好。但是,可以通过利用 Pydantic 提供的更多内置功能来简化的代码并实现想要的结果。
这是一个改进代码的更新版本,包括描述和自定义验证:
from datetime import datetime, date
from pydantic import BaseModel, validator, Field
from pydantic.types import Annotated
class TimestampWithSplit(BaseModel):
date: Annotated[
date,
Field(
description="ISO format date (YYYY-MM-DD). Single-digit days and months are allowed.",
example="2021-7-1"
)
]
time: Annotated[
time,
Field(
description="ISO format time (HH:MM:SS).",
example="12:36:23"
)
]
@validator("date", pre=True)
def parse_date(cls, value: str) -> date:
try:
return datetime.strptime(value, "%Y-%m-%d").date()
except ValueError:
raise ValueError("Invalid date format. Please use YYYY-MM-DD.")
@root_validator(pre=True)
def combine_datetime(cls, values: dict) -> datetime:
if "date" in values and "time" in values:
values["root"] = datetime.combine(values["date"], values["time"])
return values
class Config:
schema_extra = {
"properties": {
"date": {"description": "ISO format date (YYYY-MM-DD). Single-digit days and months are allowed."},
"time": {"description": "ISO format time (HH:MM:SS)."},
}
}
让我们分解一下这段代码:
-
description
在Field
中: 我们直接在date
和time
字段中使用 Pydantic 的Field
类来提供描述。这使的代码更简洁易读。 -
example
在Field
中: 与description
类似,我们还可以在Field
中提供example
,以便在生成的架构中包含它。 -
@validator
用于自定义验证:@validator("date", pre=True)
装饰器用于在解析输入字符串之前添加自定义验证逻辑。pre=True
确保此验证器在任何其他验证之前运行。 -
@root_validator
用于组合值:@root_validator(pre=True)
装饰器允许在所有字段验证后处理所有输入数据。我们使用它来组合date
和time
字段以创建datetime
对象,并将其存储在名为root
的字段中。 -
schema_extra
用于其他架构修改:Config
类中的schema_extra
属性允许自定义生成的 JSON 模式。在这里,我们添加了日期和时间字段的描述。
现在,当使用
TimestampWithSplit.model_json_schema()
时,生成的架构将包含添加的描述以及
date
和
time
字段的示例。
此设置还将使用的自定义验证逻辑正确解析日期,并且
model_validate_json
将返回一个带有
root
作为组合
datetime
对象的字典。
例如:
data = {"date": "2021-7-1", "time": "12:36:23"}
timestamp_obj = TimestampWithSplit.model_validate_json(data)
print(timestamp_obj) # 输出:TimestampWithSplit(date=datetime.date(2021, 7, 1), time=datetime.time(12, 36, 23))
print(timestamp_obj.root) # 输出:2021-07-01 12:36:23
此解决方案使的代码更简洁、更易读,同时利用 Pydantic 的内置功能来实现想要的结果。
标签:python,pydantic From: 79020189