フォームモデル¶
AI coding agents
Use the official FastAPI skill for your installed version. Install it from your project directory:
uvx library-skills
See Develop with AI.
🌐 AI と人間による翻訳
この翻訳は、人間のガイドに基づいて AI によって作成されました。🤝
原文の意図を取り違えていたり、不自然な表現になっている可能性があります。🤖
AI LLM をより適切に誘導するのを手伝う ことで、この翻訳を改善できます。
FastAPI では、フォームフィールドを宣言するために Pydantic モデルを使用できます。
備考
これは FastAPI バージョン 0.113.0 以降でサポートされています。🤓
フォーム用の Pydantic モデル¶
受け取りたいフィールドを フォームフィールド として持つ Pydantic モデル を宣言し、パラメータを Form として宣言するだけです:
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
@app.post("/login/")
async def login(data: Annotated[FormData, Form()]):
return data
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
@app.post("/login/")
async def login(data: FormData = Form()):
return data
FastAPI はリクエストの フォームデータ から 各フィールド のデータを 抽出 し、定義した Pydantic モデルとして渡します。
HTML チェックボックスには、デフォルト値を False とした真偽値フィールドを宣言します。
ドキュメントで確認¶
/docs のドキュメント UI で確認できます:
追加のフォームフィールドを禁止¶
一部の特殊なユースケース(おそらくあまり一般的ではありません)では、フォームフィールドを Pydantic モデルで宣言したもののみに制限し、追加のフィールドを禁止したい場合があります。
備考
これは FastAPI バージョン 0.114.0 以降でサポートされています。🤓
Pydantic のモデル設定で、extra フィールドを forbid にできます:
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
model_config = {"extra": "forbid"}
@app.post("/login/")
async def login(data: Annotated[FormData, Form()]):
return data
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class FormData(BaseModel):
username: str
password: str
model_config = {"extra": "forbid"}
@app.post("/login/")
async def login(data: FormData = Form()):
return data
クライアントが余分なデータを送信しようとすると、エラーのレスポンスを受け取ります。
例えば、クライアントが次のフォームフィールドを送ろうとした場合:
username:Rickpassword:Portal Gunextra:Mr. Poopybutthole
フィールド extra は許可されていない旨のエラーレスポンスが返されます:
{
"detail": [
{
"type": "extra_forbidden",
"loc": ["body", "extra"],
"msg": "Extra inputs are not permitted",
"input": "Mr. Poopybutthole"
}
]
}
フォームモデルの組み合わせ¶
複数のフォームモデルと個別の Form パラメータを組み合わせることができます。
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
class Preferences(BaseModel):
tags: list[str] = []
@app.post("/profiles/")
async def create_profile(
profile: Annotated[Profile, Form()],
preferences: Annotated[Preferences, Form()],
token: Annotated[str, Form()],
):
return {"profile": profile, "preferences": preferences, "token": token}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
class Preferences(BaseModel):
tags: list[str] = []
@app.post("/profiles/")
async def create_profile(
profile: Profile = Form(),
preferences: Preferences = Form(),
token: str = Form(),
):
return {"profile": profile, "preferences": preferences, "token": token}
クライアントは name、tags、token をフォームフィールドとして送信します。各モデルはフォームフィールドを個別に検証します。
各モデルの extra 設定は、他のパラメータや依存関係で宣言されたフィールドやファイルを含む、すべてのフォームフィールドに適用されます。extra="forbid" では、そのモデルにないフィールドはすべて拒否されます。extra="allow" では、それらのフィールドはモデルの追加データとして含まれます。
複数の宣言で同じフォームフィールド名を使用すると、それぞれがそのフィールドの値を検証します。OpenAPI スキーマで一貫した記述ができるように、共有フィールドには互換性のある型と制約を使用してください。
オプションのフォームモデル¶
フォームモデルに | None とデフォルト値 None を指定して宣言すると、フィールドのグループをオプションにできます。
from typing import Annotated
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
age: int
@app.post("/profiles/")
async def create_profile(
token: Annotated[str, Form()],
profile: Annotated[Profile | None, Form()] = None,
):
return {"token": token, "profile": profile}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
age: int
@app.post("/profiles/")
async def create_profile(
token: str = Form(),
profile: Profile | None = Form(default=None),
):
return {"token": token, "profile": profile}
name も age も送信されない場合、profile は None になります。どちらかが送信された場合、FastAPI はモデルを検証し、両方のフィールドを必須とします。空の値を送信した場合も、フィールドが指定されたものとして扱われます。
デフォルト値なしで | None を使用した場合、パラメータは必須のままです。
追加のフィールドはモデルの extra 設定に従います。無視された追加フィールドによって、モデルが指定されたことにはなりません。
チェックされていないチェックボックスのみを含むオプションのモデルは省略されます。明示的に指定するには、enabled=false などの値を送信してください。
フォームモデルのオプションの Union¶
モデルのオプションの Union も使用できます。
from typing import Annotated, Literal
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Person(BaseModel):
kind: Literal["person"]
name: str
class Company(BaseModel):
kind: Literal["company"]
company_name: str
@app.post("/contacts/")
async def create_contact(
contact: Annotated[Person | Company | None, Form(discriminator="kind")] = None,
):
return contact
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from typing import Literal
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Person(BaseModel):
kind: Literal["person"]
name: str
class Company(BaseModel):
kind: Literal["company"]
company_name: str
@app.post("/contacts/")
async def create_contact(
contact: Person | Company | None = Form(default=None, discriminator="kind"),
):
return contact
フォームフィールドが送信されない場合、contact は None になります。kind=person と name、または kind=company と company_name を送信してください。判別子によって検証するモデルが選択されます。
フォームモデルの Union の組み合わせ¶
Union を他のフォームモデル、個別の Form パラメータ、File パラメータと組み合わせることができます。各 Union は個別に検証されます。
from typing import Annotated, Literal
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Person(BaseModel):
contact_type: Literal["person"]
name: str
class Company(BaseModel):
contact_type: Literal["company"]
company_name: str
class Email(BaseModel):
notification_type: Literal["email"]
email: str
class SMS(BaseModel):
notification_type: Literal["sms"]
phone: str
@app.post("/contacts/")
async def create_contact(
contact: Annotated[Person | Company, Form(discriminator="contact_type")],
token: Annotated[str, Form()],
notification: Annotated[
Email | SMS | None, Form(discriminator="notification_type")
] = None,
):
return {"contact": contact, "notification": notification, "token": token}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from typing import Literal
from fastapi import FastAPI, Form
from pydantic import BaseModel
app = FastAPI()
class Person(BaseModel):
contact_type: Literal["person"]
name: str
class Company(BaseModel):
contact_type: Literal["company"]
company_name: str
class Email(BaseModel):
notification_type: Literal["email"]
email: str
class SMS(BaseModel):
notification_type: Literal["sms"]
phone: str
@app.post("/contacts/")
async def create_contact(
contact: Person | Company = Form(discriminator="contact_type"),
token: str = Form(),
notification: Email | SMS | None = Form(
default=None, discriminator="notification_type"
),
):
return {"contact": contact, "notification": notification, "token": token}
すべてのフィールドを同じフォームで送信してください。例えば、contact_type=person、name=Rick、notification_type=email、email=rick@example.com、token=secret を送信します。
notification を None のままにするには、通知用のフィールドを省略してください。
フォームモデルとファイル¶
フォームモデルをファイルパラメータと組み合わせることもできます。
from typing import Annotated
from fastapi import FastAPI, Form, UploadFile
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
@app.post("/profiles/")
async def create_profile(profile: Annotated[Profile, Form()], avatar: UploadFile):
return {"profile": profile, "filename": avatar.filename}
🤓 Other versions and variants
Tip
Prefer to use the Annotated version if possible.
from fastapi import FastAPI, File, Form, UploadFile
from pydantic import BaseModel
app = FastAPI()
class Profile(BaseModel):
name: str
@app.post("/profiles/")
async def create_profile(profile: Profile = Form(), avatar: UploadFile = File()):
return {"profile": profile, "filename": avatar.filename}
ここでは、クライアントは multipart/form-data を使用して name フィールドと avatar ファイルを送信します。
まとめ¶
FastAPI でフォームフィールドを宣言するために Pydantic モデルを使用できます。😎