set
类型的字段已经 JSON 序列化为列表。然而,这些列表是无序的。或者,更具体地说,他们的项目是根据原始集合的内部排序进行排序的。不幸的是,即使两个集合包含相同的项目,它们的内部顺序可能仍然不同。因此,在没有显式排序的情况下序列化集合会产生不确定的结果。
问题
set
的所有字段首先 JSON 序列化为排序列表,然后再将结果转换为字符串。我想避免定义自定义设置类型或为每个此类属性添加自定义类型注释。该解决方案应该更通用,因为可能需要这种处理的属性数量更大。此外,它们也可能在该特定模型的子类中定义。有没有一种相当简单的方法来实现这一目标?
选项
set
类型的所有属性定义自定义序列化函数来实现所需的效果。然而,在 Pydantic 2 中,由于“性能开销和实现复杂性”,该选项已被“删除”。好像可以理解。我不一定要寻找一种模仿 Pydantic 1 行为的方法。如果有一种方法可以使用主要或推荐的 Pydantic 2 功能实现类似的效果,我更愿意使用它。 似乎在 JSON 序列化的某个时刻,Pydantic 无论如何都会将集合转换为列表。在理想情况下,我想以某种方式利用这种转换,并仅就其结果调用
sorted
将
@field_serializer
装饰器来完成。来源:pydantic 文档 > 函数序列化器 这是参考文档中给出的示例:
from typing import Set
from pydantic import BaseModel, field_serializer
class StudentModel(BaseModel):
name: str = 'Jane'
courses: Set[str]
@field_serializer('courses', when_used='json')
def serialize_courses_in_order(courses: Set[str]):
return sorted(courses)
student = StudentModel(courses={'Math', 'Chemistry', 'English'})
print(student.model_dump_json())
#> {"name":"Jane","courses":["Chemistry","English","Math"]}
属性
courses
被序列化为排序列表。
您还可以一次提供多个属性:
class AnotherModel(BaseModel):
a: Set[str]
b: Set[str]
@field_serializer('a', 'b', when_used='json')
def serialize_sets(set_of_str: Set[str]):
return sorted(set_of_str)
(我认为要概述 pydantic 的众多功能并不是一件容易的事。我花了一些时间才发现这一点😉)