pydantic
Deserialization pit: TypeError: Object of type 'datetime' is not JSON serializable
Problem Description
There are the following requirements:
import requests
requests.post('http://localhost/upload/', json=data)
data should be a dict type
The value of data should not have detetime type, if there is datetime it should be converted to 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())
The above code will report an error: TypeError: Object of type ‘datetime‘ is not JSON serializable
why? Because data should be a dict, the value of releaseDate should be converted to str, not datetime
And pydantic's dict() will only convert the value of releaseDate to datetime instead of str
So, we need to modify the code:
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))
The json of the pydantic model will convert the datetime type field to str
The solution is:
- First call the json method of pydantic to serialize the object into a string. ( pydantic object -> str )
- Deserialize the string into a dict dictionary by calling the loads method of the json library. ( str->dict )
It's very convoluted, isn't it? No way!
Of course, if you don't want to use it in requests, but just want to serialize it into a json string, you can use the pydantic prepared for you pydantic_encoder
, the usage is as follows:
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) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。