pydantic
反序列化的坑:TypeError: Object of type ‘datetime‘ is not JSON serializable
问题描述
有如下需求:
import requests
requests.post('http://localhost/upload/', json=data)
data 应该是一个 dict 类型
data 的 value 不应该有 detetime 类型,如果有 datetime 应该转为 str
from datetime import datetime, timezone
from datetime import datetime
from pydantic import BaseModel, Field
import requests
import json
def get_utc_now_timestamp() -> datetime:
return datetime.utcnow().replace(tzinfo=timezone.utc)
class Struct(BaseModel):
author: str = Field(...)
releaseDate: datetime = Field(...)
data = Struct(
author='jike',
releaseDate=get_utc_now_timestamp()
)
requests.post('http://localhost/upload/', json=data.dict())
上面的代码会报错:TypeError: Object of type ‘datetime‘ is not JSON serializable
为什么呢?因为 data 应该是一个 dict ,其中的 releaseDate 的 value 应该转为 str ,而不能是 datetime
而 pydantic 的 dict() 只会把 releaseDate 的 value 转为 datetime 而不是 str
所以,我们需要修改代码:
from datetime import datetime, timezone
from datetime import datetime
from pydantic import BaseModel, Field
import requests
import json
def get_utc_now_timestamp() -> datetime:
return datetime.utcnow().replace(tzinfo=timezone.utc)
class Struct(BaseModel):
author: str = Field(...)
releaseDate: datetime = Field(...)
data = Struct(
author='jike',
releaseDate=get_utc_now_timestamp()
).json(ensure_ascii=False)
requests.post('http://localhost/upload/', json=json.loads(data))
pydantic 模型的 json 会把 datetime 类型的字段转为 str
解决方案就是:
- 先调用 pydantic 的 json 方法把对象序列化为字符串。 ( pydantic object -> str )
- 在调用 json 库的 loads 方法把字符串反序列化为 dict 字典。( str-> dict )
很绕是吧!没办法呢!
当然,如果你并不是想在 requests 中使用,而是仅仅想做序列化为 json 字符串,那可以使用 pydantic 给你准备好的 pydantic_encoder
, 用法如下:
from datetime import datetime, timezone
from datetime import datetime
from loguru import logger
from pydantic import BaseModel, Field
import json
from pydantic.json import pydantic_encoder
def get_utc_now_timestamp() -> datetime:
return datetime.utcnow().replace(tzinfo=timezone.utc)
class Struct(BaseModel):
author: str = Field(...)
releaseDate: datetime = Field(...)
data = Struct(
author='jike',
releaseDate=get_utc_now_timestamp()
)
logger.debug(json.dumps(data.dict(),default=pydantic_encoder))
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。