我为日期时间创建了一个 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"])
我现在正在尝试做两件事:
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
返回 model_validate_json
,同时还自定义 JSON 架构和日期验证?
我可能不清楚你的目标,所以如果这不适用,我很抱歉,但看起来你最好使用带有
BaseModel
和 date
属性的 time
而不是使用你的 RootModel
解决方案。给定这样的代码:
import datetime
from pydantic import BaseModel, Field, computed_field, field_validator
class TimestampWithSplit(BaseModel):
date: datetime.date = Field(
..., description="ISO format date", repr=False, exclude=True
)
time: datetime.time = Field(
..., description="ISO format time", repr=False, exclude=True
)
@computed_field
@property
def timestamp(self) -> datetime.datetime:
return datetime.datetime.combine(self.date, self.time)
我们可以从字典中初始化它:
>>> t=TimestampWithSplit.model_validate({'date': '2024-09-24', 'time': '11:00:00'})
>>> t
TimestampWithSplit(timestamp=datetime.datetime(2024, 9, 24, 11, 0))
我们可以使用关键字参数来初始化它:
>>> t=TimestampWithSplit(date='2024-09-24', time='11:00:00')
>>> t
TimestampWithSplit(timestamp=datetime.datetime(2024, 9, 24, 11, 0))
如果您想支持单位数月/日,例如
2024-9-1
,您可以为 date
字段添加字段验证器。也许是这样的:
@field_validator("date", mode="before")
@classmethod
def validate_date(cls, v: str | datetime.date) -> datetime.date:
if isinstance(v, datetime.date):
return v
elif isinstance(v, str):
return datetime.datetime.strptime(v, "%Y-%m-%d").date()
else:
raise ValueError("invalid date")
这将为您提供所需的架构:
>>> print(json.dumps(t.schema(), indent=2))
{
"properties": {
"date": {
"description": "ISO format date",
"format": "date",
"title": "Date",
"type": "string"
},
"time": {
"description": "ISO format time",
"format": "time",
"title": "Time",
"type": "string"
}
},
"required": [
"date",
"time"
],
"title": "TimestampWithSplit",
"type": "object"
}
且该类型的序列化仅包括组合
timestamp
:
>>> t.model_dump_json()
'{"timestamp":"2024-09-24T11:00:00"}'