如何在Pydantic 2中将set类型字段序列化为有序列表?
问题背景
在Pydantic 2中,set类型字段会被JSON序列化为列表,但这些列表的顺序依赖集合内部的排序规则,是无序且不确定的——即使两个集合包含完全相同的元素,序列化后的列表顺序也可能不同。
需求
希望为某个Pydantic 2模型配置全局规则,将其所有set类型字段先序列化为有序列表,再完成后续序列化。要求避免定义自定义set类型,也不为每个set属性单独添加自定义注解(需处理的属性数量多,且可能存在于模型的子类中)。
可选思路分析
- 原本考虑用模型序列化器,但需要手动遍历所有属性、检查类型、调用元素序列化逻辑再排序,操作繁琐,希望能复用Pydantic对字段类型的内置判断来简化流程。
- Pydantic 1中可以通过
json_encoders配置全局处理set类型,但Pydantic 2已移除该功能(官方出于性能和实现复杂度考量),因此倾向于使用Pydantic 2的原生特性实现。理想状态是在Pydantic将集合转换为列表的环节介入,仅对结果调用sorted()方法。
解决方案
可以通过全局字段序列化器实现,在父模型中定义一个通用的序列化逻辑,自动匹配所有set类型字段并排序,子类继承后即可自动生效:
from pydantic import BaseModel, field_serializer from typing import Set, Any class BaseSortedSetModel(BaseModel): @field_serializer('*', when_used='always') def handle_sets(self, value: Any, info) -> Any: # 判断当前字段是否为set类型(兼容泛型Set[T]) annotation = info.field.annotation if (hasattr(annotation, '__origin__') and annotation.__origin__ is set): return sorted(value) # 非set类型字段沿用默认序列化逻辑 return value # 测试示例子类 class UserTags(BaseSortedSetModel): name: str tags: Set[str] scores: Set[int] # 验证效果 user = UserTags(name="Alice", tags={"python", "pydantic", "dev"}, scores={90, 80, 95}) print(user.model_dump_json(indent=2))
代码说明
@field_serializer('*', when_used='always'):*表示匹配模型所有字段,when_used='always'确保无论字段是否为默认值都会触发该序列化逻辑。- 类型判断:通过
info.field.annotation获取字段的注解类型,检查其__origin__是否为set,兼容Set[str]、Set[int]等泛型集合类型。 - 排序处理:对
set类型的字段值调用sorted(),将无序集合转换为有序列表,其他字段沿用Pydantic默认序列化逻辑。
优势
- 无需自定义
set类型或逐个字段添加注解,一次配置即可覆盖父模型及所有子类的set字段。 - 完全复用Pydantic的原生序列化流程,仅在必要环节介入排序,性能开销低。
内容的提问来源于stack exchange,提问作者Peter Bašista
相关产品推荐
相关产品推荐

