最直接推荐的方式是使用 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 是独立配置,无需捆绑。