pydantic-v2 について
Python 開発者向けに、Pydantic v2 のデータモデル作成と検証を案内するリファレンススキルです。v2 API、シリアライズ、v1 からの移行時の注意点を扱います。
主な機能
- 01型付きモデルとフィールド制約
- 02フィールドおよびモデルバリデーター
- 03シリアライズと計算フィールド
- 04環境変数と .env から設定を読み込み
- 05TypeAdapter とユニオン型の検証
- 06v1 から v2 への移行ガイド
活用シーン
- 01検証付き DTO や設定モデルの定義
- 02フィールド単位または複数フィールドの検証追加
- 03API やデータ交換向けのモデルシリアライズ
- 04環境変数からアプリ設定を読み込み
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bm629/ agent-skills --skill pydantic-v2インストール後、Claude Code で/pydantic-v2を入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/migration-v1-to-v2.mdserialization.mdsettings.mdsources.mdvalidators.md詳細
Pydantic v2
概要
Pydantic v2 は、Python の型ヒントに基づいてデータを検証し、シリアライズします。BaseModel
のサブクラスでは、アノテーションとしてフィールドを宣言します。インスタンスを生成すると入力が検証・変換され、model_dump* を使ってインスタンスを dict/JSON に変換できます。このスキルは、現在の v2 を記述するために必要な知識の差分、つまり v1 以降の API(model_config = ConfigDict(...)、model_dump()、@field_validator)と、v1 の慣れた書き方が残っていると陥りやすい落とし穴を扱います。スタンドアロンの Pydantic、すなわちモデル、フィールド、バリデーター、シリアライズ、設定、pydantic-settings、TypeAdapter、構造化型/ユニオン型を対象とします。フレームワークレベルのリクエスト/レスポンスモデル化と response_model については、fastapi スキルを参照してください。このスキルでは、フレームワーク固有の仕組みを重複して説明しません。
有効化するタイミング
- ✅ 型付きフィールドと制約を持つデータモデル、設定オブジェクト、または DTO を定義するとき。
- ✅ フィールドレベルまたはモデルレベルの検証、カスタムシリアライズ、計算フィールドを記述するとき。
- ✅
pydantic-settingsで環境変数/.envからアプリケーション設定を読み込むとき。 - ✅
TypeAdapterでモデル以外の形状(list[Model]、dict、プリミティブ値)を一括検証するとき。 - ✅ v1 時代のコード(
class Config、.dict()、@validator)を v2 にモダナイズするとき。
有効化しないでください:
- タスクが FastAPI のリクエスト/レスポンスの接続や
response_modelに関する場合は、fastapiスキルを使用してください。 - トピックが Pydantic-AI エージェントや Logfire の計測に関する場合は、別の製品のため対象外です。
ワークフロー
ステップ 1:型ヒントでモデルを定義する
フィールドは name: Type の形式です。デフォルト値がなければ必須です。デフォルト値を指定すると省略可能になります。v2 では特に、Optional[int](つまり int | None)はフィールドを null 許容にするだけで、デフォルト値は設定しません。デフォルト値を省略した場合、フィールドは引き続き必須です。ミュータブルなデフォルト値には default_factory を使ってください(インスタンス間で共有されるリテラルの []/{} は使わないでください)。
from pydantic import BaseModel, Field
class User(BaseModel):
id: int # required
name: str = "anon" # optional, has default
nickname: str | None = None # nullable AND optional (explicit default)
tags: list[str] = Field(default_factory=list) # safe mutable default
信頼できるキーワード引数(User(id=1))からインスタンスを生成するか、クラスメソッドの User.model_validate(obj)(dict/オブジェクト)および User.model_validate_json(data)(JSON の str/bytes)で信頼できない入力を検証します。model_construct(**data) は検証を省略するため、信頼できるデータにのみ使用してください。
ステップ 2:Annotated[..., Field(...)] でフィールドに制約を設定する
Annotated スタイルを優先してください。型を正確に保ち、ほかの型ときれいに組み合わせられます。Field には gt/ge/lt/le/multiple_of(数値)、min_length/max_length/pattern(文字列)のほか、default、default_factory、description、alias、exclude を指定できます。
from typing import Annotated
from pydantic import BaseModel, Field
class Account(BaseModel):
balance: Annotated[int, Field(ge=0)]
handle: Annotated[str, Field(min_length=3, max_length=32, pattern=r"^[a-z0-9_]+$")]
score: Annotated[float, Field(default=0.0, le=100.0)]
ステップ 3:@field_validator/@model_validator で検証する
フィールドバリデーターはフィールドごとに実行され、モデルバリデーターはフィールドをまたいで実行されます。before/after/plain/wrap モード、ValidationInfo、および @classmethod のルールについては、references/validators.md を参照してください。
from typing_extensions import Self
from pydantic import BaseModel, field_validator, model_validator
class Signup(BaseModel):
email: str
password: str
password_repeat: str
@field_validator("email", mode="after")
@classmethod
def lowercase(cls, v: str) -> str:
return v.lower()
@model_validator(mode="after")
def passwords_match(self) -> Self:
if self.password != self.password_repeat:
raise ValueError("passwords do not match")
return self
ステップ 4:model_dump* でシリアライズする
model_dump() → dict、model_dump_json() → JSON 文字列です。include/exclude/exclude_unset/exclude_defaults/exclude_none/by_alias/mode で出力形式を調整します。@field_serializer でカスタマイズし、@computed_field で派生出力を追加できます。references/serialization.md を参照してください。
user.model_dump() # dict, python types
user.model_dump(exclude={"password"}) # drop a field
user.model_dump(exclude_unset=True) # only explicitly-set fields (PATCH-style)
user.model_dump_json(by_alias=True, exclude_none=True, indent=2)
ステップ 5:model_config = ConfigDict(...) で設定する
クラス属性 model_config(ネストした class Config ではありません)に ConfigDict を設定します。よく使うオプションは、strict、from_attributes(ORM オブジェクトから読み込み)、validate_assignment、use_enum_values、extra("ignore"/"allow"/"forbid")、frozen、str_strip_whitespace です。名前によるエイリアス指定では、現在の 2.11 以降は validate_by_name=True(validate_by_alias=True と併用)を推奨します。落とし穴の項を参照してください。
from pydantic import BaseModel, ConfigDict
class Row(BaseModel):
model_config = ConfigDict(from_attributes=True, extra="forbid", frozen=True)
id: int
label: str
obj = Row.model_validate(orm_row) # from_attributes reads attributes off an ORM object
ステップ 6:pydantic-settings で設定を読み込む
BaseSettings は独立した pydantic-settings パッケージ(コアの pydantic には含まれません)にあります。環境変数や .env からフィールドを読み込みます。SettingsConfigDict で設定します。ネストされた設定やソースの優先順位については、references/settings.md を参照してください。
from pydantic_settings import BaseSettings, SettingsConfigDict
class Settings(BaseSettings):
model_config = SettingsConfigDict(env_prefix="APP_", env_file=".env",
env_file_encoding="utf-8")
api_key: str # required → from APP_API_KEY
host: str = "127.0.0.1"
port: int = 8000 # coerced from the string env value
settings = Settings() # reads env / .env at construction
ステップ 7:構造 — 列挙型、Literal、ユニオン、TypeAdapter
あるモデルを別のモデルのフィールド型として使用し、モデルをネストします。固定の選択肢には Enum(JSON と親和性の高い値にする場合は str, Enum を継承)または Literal を使用します。
判別可能なユニオンでは、Field(discriminator=...) を使ってタグフィールドに基づき振り分けます。モデル以外の形状(リスト、辞書、プリミティブ)は TypeAdapter で検証します。まとめて行う検証や単独の検証には、RootModel よりも v2 に適した選択肢です。
from typing import Annotated, Literal
from pydantic import BaseModel, Field, TypeAdapter
class Cat(BaseModel):
kind: Literal["cat"]
lives: int
class Dog(BaseModel):
kind: Literal["dog"]
good_boy: bool = True
class Owner(BaseModel):
pet: Annotated[Cat | Dog, Field(discriminator="kind")]
cats = TypeAdapter(list[Cat]).validate_python([{"kind": "cat", "lives": 9}])
ステップ 8:ValidationError を処理する
model_validate* とインスタンスの構築は、入力が不正な場合に ValidationError を発生させます。
.errors() は辞書のリスト(type、loc、msg、input、url)を返し、.error_count() は件数を返します。.json() はそれらをシリアライズします。
from pydantic import ValidationError
try:
User.model_validate({"id": "not-an-int"})
except ValidationError as e:
for err in e.errors():
print(".".join(map(str, err["loc"])), err["type"], err["msg"])
ルール
必ず守るルール(違反禁止):
- v2 API のみを使用します。
model_config = ConfigDict(...)、model_dump()/model_dump_json()、model_validate()/model_validate_json()、@field_validator/@model_validator、model_json_schema()を使用します。class Config、.dict()/.json()、@validator/@root_validator、.parse_obj()/.parse_raw()、.schema()は使用しないでください。 @field_validatorの直下には@classmethodを置く必要があります。@model_validator(mode="after")はselfに対して動作するため、@classmethodは不要です。Optional[x]はデフォルト値ではありません。 フィールドを省略可能にする場合は、x | None = Noneのように明示的に指定します。- 可変なデフォルト値には
default_factoryを使い、[]/{}/dict()を直接指定しないでください。 BaseSettingsはpydanticではなくpydantic_settingsからインポートします。BaseModel内のフィールド注釈にTypeAdapterを使用しないでください。 モデル以外の型の検証には、単独で使用します。
推奨事項(変更可能):
Field(...)をデフォルト値として割り当てるより、Annotated[T, Field(...)]を優先します。- 1 つのモデルをリクエストとレスポンスの両方に使い回さず、それぞれ別のモデルを用意します。
- 頻繁に実行される処理では、
TypeAdapterのインスタンスを再利用します(1 回作成し、複数回検証します)。
注意点
populate_by_nameは廃止に向かっています。 Pydantic 2.11+ では、代わりにConfigDict(validate_by_name=True, validate_by_alias=True)を使用します。populate_by_nameは 2.x でも引き続き動作します(v3 で非推奨になる予定です)。古い 2.x では問題ありませんが、現在のバージョンでは新しい 2 つの設定を記述してください。class Configは非推奨ですが、引き続き警告なく動作します。 エラーにならないため、v1 のコードは「問題なさそう」に見えても、推奨されない書き方であり、v2 のオプションも利用できません。model_config = ConfigDict(...)に置き換えてください。@field_validatorに@classmethodを付け忘れると、 クラス定義時にエラーになったり、正しく動作しなかったりします。デコレーターは上から@field_validator(...)、その直下に@classmethodの順にします。model_configに通常のdictを使うと動作しますが、型チェッカーの支援が失われます。 IDE やty/ mypy でキーを検証できるよう、ConfigDict(...)コンストラクターを使用してください。- 緩やかな型変換には注意してください。 デフォルトでは
"123"は123に変換されます。厳密な検証が必要な場合は、ConfigDict(strict=True)(またはフィールドごとにField(strict=True))を設定します。 exclude_unsetとexclude_defaultsは異なります。exclude_unsetは呼び出し元が設定していないフィールドを除外します(PATCH のリクエストボディに最適です)。exclude_defaultsは、設定済みであってもデフォルト値と等しいフィールドを除外します。両者は置き換え可能ではありません。
アンチパターン
- 「小さなモデルだから、古い
.dict()を使おう。」 いいえ。.dict()は実質的に削除済みで、非推奨です。model_dump()を使ってください。v1 と v2 の書き方を混在させることは、Pydantic コードが壊れる主な原因です。 - 「覚えているから」と
@root_validatorを使うこと。 v2 には存在しません。@model_validator(mode="before"|"after")を使用してください。 - リストや辞書を検証するために、単純な型をフィールド 1 つだけの
RootModelで包むこと。 代わりにTypeAdapter(list[T])を使用してください。 - FastAPI のリクエスト/レスポンス処理をここで再実装すること。 それは
fastapiスキルの役割です。このスキルではモデルを定義し、フレームワークがそれを利用します。
出力
ConfigDict、型付きフィールドと制約付きフィールド、@field_validator/@model_validator による検証、model_dump* によるシリアル化、pydantic-settings の設定クラス、TypeAdapter/判別可能なユニオン構造を使用した、正確で最新の Pydantic v2 ソースです。v1 時代のイディオムは一切含みません。利用者は、検証可能でシリアル化可能なデータモデルを必要とするあらゆるコードやワークフローのフェーズです。これらのモデルが HTTP API の基盤となる場合、フレームワークとの連携には fastapi スキルを使用します。
関連項目
fastapi— フレームワーク固有の内容:リクエスト/レスポンスモデル、response_model、依存性注入による検証。このスキルではモデルを定義し、fastapiがそれを使用します。ここではフレームワークの仕組みを重複して説明しないでください。- 公式ドキュメント(出典):
references/sources.mdを参照してください。
段階的な開示
詳細は references/ にあり、必要に応じて読み込みます。
references/validators.md— バリデーターを作成する場合に読み込みます。すべての@field_validator/@model_validatorのモード、ValidationInfo、@classmethodのルール、before/after の実行順序を扱います。references/serialization.md— 出力をカスタマイズする場合に読み込みます。model_dump*のすべてのキーワード引数、@field_serializer、@model_serializer、@computed_field、エイリアスの種類(validation_alias/serialization_alias/AliasChoices)を扱います。references/settings.md—pydantic-settingsの詳細を確認する場合に読み込みます。ネストされた設定、env_nested_delimiter、ソースの優先順位、secrets_dirを扱います。references/migration-v1-to-v2.md— v1 のコードを最新化する場合に読み込みます。名称変更の完全な一覧と動作の変更を扱います。references/sources.md— 調査の出典です。
本文の上限
descriptionは 1,024 文字以下(遵守済み)。- 本文は約 290 行で、5,000 トークンのソフト上限を大幅に下回ります。
- 各リファレンスファイルは、警告のしきい値である 10k トークンを大幅に下回ります。