Vu *_*ung 8 python serialization json pydantic
目前我正在使用 FastAPI 和 pydantic 作为序列化器。问题是,我们在服务器端使用雪花 id,这意味着我们需要在发送到客户端(javascript)之前将这些 id 转换为字符串,因为 id 大于 JS 的MAX SAFE INTEGER。
所以我尝试创建一个新类来扩展 python 的 int 类型并自定义它的序列化和反序列化方式。这是我的代码:
class SnowflakeId(int):
@classmethod
def __get_validators__(cls):
yield cls.validate
@classmethod
def validate(cls, v: str):
return int(v)
@classmethod
def __modify_schema__(cls, field_schema: dict) -> None:
field_schema['type'] = 'string'
Run Code Online (Sandbox Code Playgroud)
这是模型:
class BaseModel(pydantic.BaseModel):
__abstract__ = True
id: SnowflakeId
class Config:
orm_mode = True
arbitrary_types_allowed = True
json_encoders = {
SnowflakeId: lambda v: str(v)
}
alias_generator = camelize
allow_population_by_field_name = True
Run Code Online (Sandbox Code Playgroud)
当从 json 字符串反序列化为 int id 时,它工作得很好,但是,当涉及到序列化时,输出仍然是整数。我希望它也将 id 序列化为字符串,这可能吗?
是的!
json_encoders是一个很好的尝试,但是在底层 pydantic调用 json.dumps。因此,对于可序列化类型(例如您的SnowflakeId),它不会关心额外的json_encoders.
你可以做的是重写 dumps 方法:
def my_dumps(v, *, default):
for key, value in v.items():
if isinstance(value, SnowflakeId):
v[key] = str(value)
else:
v[key] = value
return json.dumps(v)
class BaseModel(pydantic.BaseModel):
id: SnowflakeId
class Config:
json_dumps = my_dumps
Run Code Online (Sandbox Code Playgroud)
让我们validate返回SnowflakeId:
class SnowflakeId(int):
...
@classmethod
def validate(cls, v: str):
return cls(v)
Run Code Online (Sandbox Code Playgroud)
m = BaseModel(id="123")
print(m.json()) # {"id": "123"}
Run Code Online (Sandbox Code Playgroud)