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

在 Pydantic v2 中,若想让某个字段**在序列化(如 .model_dump() 或 .model_dump_json())时完全不出现**,最直接、推荐的方式是使用 Field(exclude=True)。
用 Field(exclude=True) 彻底排除字段
这是官方支持的、语义明确的标准做法。被标记为 exclude=True 的字段不会出现在任何序列化结果中(无论 exclude_unset、exclude_defaults 等参数如何设置),也不会影响模型验证或初始化。
示例:
from pydantic import BaseModel, Fieldclass 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_unset 或 exclude_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是独立配置,无需捆绑。










