pydantic v2 如何让字段在序列化时完全忽略(不输出到 JSON)

最直接推荐的方式是使用 Field(exclude=True)。该方式能彻底排除字段,使其在任何序列化结果中都不出现,且不影响验证或初始化;而 exclude_unset 或 exclude_defaults 仅条件性排除,无法保证字段永远不出现。

在 Pydantic v2 中,若想让某个字段**在序列化(如 .model_dump().model_dump_json())时完全不出现**,最直接、推荐的方式是使用 Field(exclude=True)

Field(exclude=True) 彻底排除字段

这是官方支持的、语义明确的标准做法。被标记为 exclude=True 的字段不会出现在任何序列化结果中(无论 exclude_unsetexclude_defaults 等参数如何设置),也不会影响模型验证或初始化。

示例:

from pydantic import BaseModel, Field

class User(BaseModel): name: str email: str internal_id: int = Field(exclude=True) # ✅ 序列化时完全消失

user = User(name="Alice", email="a@example.com", internal_id=123) print(user.model_dump

()) # {'name': 'Alice', 'email': 'a@example.com'} print(user.model_dump_json()) # {"name":"Alice","email":"a@example.com"}

避免误用 exclude_unsetexclude_defaults

这两个参数控制的是“条件性排除”,不是字段本身的属性:

  • exclude_unset=True:只对未显式赋值(即使用默认值且未传参)的字段生效;一旦你传了 internal_id=123,它就会出现在输出里。
  • exclude_defaults=True:仅当字段值等于其默认值(包括 DefaultFactory 生成的)时才排除;对非默认值无效。
  • 它们都不能保证字段“永远不出现”,所以不能替代 Field(exclude=True)

其他场景补充说明

如果你需要更细粒度控制(比如仅在 JSON 中排除、或按不同模式切换),可考虑:

  • 自定义 model_dump 调用:显式传入 exclude={'internal_id'},但这是调用侧控制,不改变字段定义本身。
  • @computed_field + exclude=True:适用于动态计算且不应序列化的字段。
  • 私有字段(_xxx)不会自动排除:Pydantic v2 不再按命名约定自动忽略下划线字段,必须显式声明 Field(exclude=True) 才行。

不推荐的写法(易出错)

不要依赖以下方式:

  • internal_id: Optional[int] = None + exclude_unset:不可靠,一旦赋值就暴露。
  • 重写 __pydantic_core_schema__ 或魔改序列化逻辑:过度复杂,破坏可维护性。
  • Field(default=None, exclude=True) 混合写法:exclude=True 已足够,default 是独立配置,无需捆绑。