如何序列化在Pydantic中扩展内置类型的自定义类型?

发布于 2025-01-31 20:56:49 字数 1139 浏览 3 评论 0 原文

目前,我正在与Fastapi和Pydantic合作作为Serialializer。 问题是,我们在服务器端使用雪花ID,这意味着我们需要在发送到客户端之前将这些ID转换为字符串(JavaScript),因为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'

这是模型:

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

当从JSON字符串到INT ID的次要化时,它可以正常工作,但是,当涉及序列化时,输出仍然是整数。 我希望它也将ID序列化为字符串,是否有可能?

currently I'm working with FastAPI and pydantic as serializer.
Problem is, we're using snowflake id on the server side, which means we need to convert those ids to string before sending to client (javascript) because the id is larger than JS's MAX SAFE INTEGER.

So I tried to create a new class which extends python's int type and customize how it will be serialized and deserialized. Here's my code:

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'

And here is the model:

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

It works fine when deserializing from json string into int id, however, when it comes to the serialization, the output still is integer.
I want it to serialize the id into string also, is it possible?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

与他有关 2025-02-07 20:56:49

是的!

json_encoders 是一个很好的尝试,但是在hood pydantic下调用json.dumps 。因此,对于可序列化类型(例如 snowflakeid ),它不在乎其他 json_encoders

您可以做的是覆盖转储方法:

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

validate 返回 snowflakeid

class SnowflakeId(int):
    ...

    @classmethod
    def validate(cls, v: str):
        return cls(v)
m = BaseModel(id="123")
print(m.json()) # {"id": "123"}

Yes it is!

json_encoders is a good try, however under the hood pydantic calls json.dumps. So for serializable types (like your SnowflakeId) it won't care about additional json_encoders.

What you can do is to override dumps method:

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

And let validate return SnowflakeId:

class SnowflakeId(int):
    ...

    @classmethod
    def validate(cls, v: str):
        return cls(v)
m = BaseModel(id="123")
print(m.json()) # {"id": "123"}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文