コンテンツへスキップ

レスポンスモデル - 戻り値の型

パス操作関数戻り値の型をアノテーションすることで、レスポンスに使用する型を宣言できます。

関数のパラメータで入力データに使用するのと同じ方法で型アノテーションを使用できます。Pydanticモデル、リスト、辞書、整数やブール値などのスカラー値を使用できます。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: list[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> list[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: list[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> list[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]
from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: List[str] = []


@app.post("/items/")
async def create_item(item: Item) -> Item:
    return item


@app.get("/items/")
async def read_items() -> List[Item]:
    return [
        Item(name="Portal Gun", price=42.0),
        Item(name="Plumbus", price=32.0),
    ]

FastAPI はこの戻り値の型を以下のように使用します。

  • 返されたデータを検証します。
    • データが無効な場合(例:フィールドが欠落している場合)、それはあなたのアプリコードが壊れていて、あるべきものを返していないことを意味し、不正なデータを返す代わりにサーバーエラーを返します。これにより、あなたとあなたのクライアントは、期待されるデータとデータの形式を受け取ることが保証されます。
  • OpenAPI のパス操作にレスポンスのJSON Schemaを追加します。
    • これは自動ドキュメントによって使用されます。
    • また、自動クライアントコード生成ツールによっても使用されます。

しかし、最も重要なのは

  • 出力データを戻り値の型で定義されたものに制限してフィルタリングします。
    • これは特にセキュリティにとって重要です。これについては後述します。

response_model パラメータ

型が宣言しているものと全く異なるデータを返す必要がある、またはそうしたい場合があります。

たとえば、辞書やデータベースオブジェクトを返したいが、それをPydanticモデルとして宣言したい場合があります。こうすることで、Pydanticモデルが、返されたオブジェクト(例:辞書やデータベースオブジェクト)のすべてのデータドキュメント、検証などを実行します。

戻り値の型アノテーションを追加した場合、ツールやエディタは、関数が宣言したもの(例:Pydanticモデル)とは異なる型(例:辞書)を返していることを示す(正しい)エラーを表示します。

そのような場合は、戻り値の型の代わりに、パス操作デコレータパラメータの response_model を使用できます。

response_model パラメータは、以下のどのパス操作でも使用できます。

  • @app.get()
  • @app.post()
  • @app.put()
  • @app.delete()
  • など
from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float | None = None
    tags: list[str] = []


@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item


@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]
🤓 その他のバージョンとバリアント
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: list[str] = []


@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item


@app.get("/items/", response_model=list[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]
from typing import Any, List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: Union[float, None] = None
    tags: List[str] = []


@app.post("/items/", response_model=Item)
async def create_item(item: Item) -> Any:
    return item


@app.get("/items/", response_model=List[Item])
async def read_items() -> Any:
    return [
        {"name": "Portal Gun", "price": 42.0},
        {"name": "Plumbus", "price": 32.0},
    ]

注記

response_model は、すべてのパラメータやボディとは異なり、「デコレータ」メソッド(getpostなど)のパラメータであることに注意してください。

response_model は、Pydanticモデルフィールドに宣言するのと同じ型を受け取ります。したがって、Pydanticモデルであることもありますが、たとえば List[Item] のようなPydanticモデルのlistであることもあります。

FastAPI はこの response_model を使用して、すべてのデータドキュメント、検証などを行い、出力データをその型宣言に変換およびフィルタリングします。

ヒント

エディタ、mypy などで厳密な型チェックを行っている場合は、関数の戻り値の型を Any として宣言できます。

これにより、意図的に何でも返すことをエディタに伝えます。しかし、FastAPI は引き続き response_model を使用してデータのドキュメント、検証、フィルタリングなどを行います。

response_model の優先順位

戻り値の型と response_model の両方を宣言した場合、response_model が優先され、FastAPI で使用されます。

これにより、応答モデルとは異なる型を返す場合でも、エディタや mypy などのツールで使用するために、関数に正しい型アノテーションを追加できます。それでも、FastAPI で response_model を使用してデータの検証、ドキュメント化などを実行できます。

また、response_model=None を使用して、そのパス操作の応答モデルの作成を無効にすることもできます。これは、有効な Pydantic フィールドではないものに対して型アノテーションを追加している場合に必要になることがあります。その例を以下のセクションで示します。

同じ入力データを返す

ここでは UserIn モデルを宣言しています。これにはプレーンテキストのパスワードが含まれます。

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user

情報

EmailStr を使用するには、まず email-validator をインストールしてください。

仮想環境を作成し、アクティブ化してからインストールしてください。たとえば、

$ pip install email-validator

または

$ pip install "pydantic[email]"

そして、このモデルを入力として宣言し、同じモデルを出力として宣言しています。

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


# Don't do this in production!
@app.post("/user/")
async def create_user(user: UserIn) -> UserIn:
    return user

これで、ブラウザがパスワード付きのユーザーを作成するたびに、API は同じパスワードをレスポンスで返します。

この場合、同じユーザーがパスワードを送信しているので、問題にはならないかもしれません。

しかし、同じモデルを別のパス操作に使用すると、ユーザーのパスワードをすべてのクライアントに送信してしまう可能性があります。

危険

すべての注意点を理解し、何をしているのか分かっている場合を除き、ユーザーのプレーンパスワードを保存したり、このようにレスポンスで送信したりしないでください。

出力モデルを追加する

代わりに、平文パスワードを含む入力モデルと、パスワードを含まない出力モデルを作成できます。

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
🤓 その他のバージョンとバリアント
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

ここでは、パス操作関数がパスワードを含む同じ入力ユーザーを返しているにもかかわらず、

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
🤓 その他のバージョンとバリアント
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

... response_model をパスワードを含まない UserOut モデルと宣言しました。

from typing import Any

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: str | None = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user
🤓 その他のバージョンとバリアント
from typing import Any, Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class UserIn(BaseModel):
    username: str
    password: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserOut(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


@app.post("/user/", response_model=UserOut)
async def create_user(user: UserIn) -> Any:
    return user

そのため、FastAPI は、出力モデル (Pydantic を使用) で宣言されていないすべてのデータをフィルタリングします。

response_model または戻り値の型

この場合、2つのモデルが異なるため、関数の戻り値の型を UserOut とアノテーションした場合、エディタやツールは、クラスが異なるため無効な型を返していると不平を言います。

そのため、この例では response_model パラメータで宣言する必要があります。

...しかし、それを克服する方法については以下を読み続けてください。

戻り値の型とデータフィルタリング

前の例を続けましょう。関数を1つの型でアノテーションしたいが、関数から実際により多くのデータを含むものを返したい場合です。

FastAPI にレスポンスモデルを使用してデータをフィルタリングし続けてほしいのです。そうすれば、関数がより多くのデータを返したとしても、レスポンスにはレスポンスモデルで宣言されたフィールドのみが含まれます。

前の例では、クラスが異なっていたため、response_model パラメータを使用する必要がありました。しかし、それは、エディタやツールによる関数の戻り値の型チェックのサポートが得られないことも意味します。

しかし、このようなことをする必要があるほとんどの場合、この例のように、モデルに一部のデータをフィルタリング/削除してほしいだけです。

そのような場合、クラスと継承を使用して関数の型アノテーションを活用し、エディタとツールでより良いサポートを得ながら、FastAPI のデータフィルタリングも利用できます。

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class BaseUser(BaseModel):
    username: str
    email: EmailStr
    full_name: str | None = None


class UserIn(BaseUser):
    password: str


@app.post("/user/")
async def create_user(user: UserIn) -> BaseUser:
    return user
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel, EmailStr

app = FastAPI()


class BaseUser(BaseModel):
    username: str
    email: EmailStr
    full_name: Union[str, None] = None


class UserIn(BaseUser):
    password: str


@app.post("/user/")
async def create_user(user: UserIn) -> BaseUser:
    return user

これにより、エディタやmypyなどのツールサポートが得られます。このコードは型に関して正しいため、FastAPIのデータフィルタリングも利用できます。

これはどのように機能するのでしょうか?見てみましょう。🤓

型アノテーションとツール

まず、エディタ、mypy、その他のツールがこれをどのように認識するか見てみましょう。

BaseUser には基本フィールドがあります。そして、UserInBaseUser を継承し、password フィールドを追加するため、両方のモデルのすべてのフィールドが含まれます。

関数の戻り値の型を BaseUser とアノテーションしていますが、実際には UserIn インスタンスを返しています。

エディタ、mypy、その他のツールは、これについて苦情を言いません。なぜなら、型付けの観点から見ると、UserInBaseUser のサブクラスであり、BaseUser であるものが期待される場合に有効な型だからです。

FastAPI のデータフィルタリング

さて、FastAPI は戻り値の型を確認し、返されるデータがその型で宣言されたフィールドのみを**含む**ことを保証します。

FastAPI は Pydantic とともに内部でいくつかのことを行い、クラス継承の同じルールが返されたデータフィルタリングに使用されないようにします。そうでなければ、予想よりもはるかに多くのデータを返すことになってしまいます。

このようにして、ツールサポートデータフィルタリングの両方を備えた型アノテーションという、両方の良い点を活用できます。

ドキュメントで確認する

自動ドキュメントを見ると、入力モデルと出力モデルの両方に独自のJSON Schemaがあることを確認できます。

そして、両方のモデルがインタラクティブなAPIドキュメントに使用されます。

その他の戻り値の型アノテーション

有効な Pydantic フィールドではないものを返し、それを関数でアノテーションする場合があります。これは、ツール (エディタ、mypy など) が提供するサポートを得るためだけに行われます。

レスポンスを直接返す

最も一般的なケースは、高度なドキュメントで後述する、レスポンスを直接返すことです。

from fastapi import FastAPI, Response
from fastapi.responses import JSONResponse, RedirectResponse

app = FastAPI()


@app.get("/portal")
async def get_portal(teleport: bool = False) -> Response:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return JSONResponse(content={"message": "Here's your interdimensional portal."})

この単純なケースは、戻り値の型アノテーションが Response クラス (またはそのサブクラス) であるため、FastAPI によって自動的に処理されます。

RedirectResponseJSONResponse の両方が Response のサブクラスであるため、型アノテーションは正しく、ツールも問題なく動作します。

レスポンスサブクラスをアノテーションする

型アノテーションで Response のサブクラスを使用することもできます。

from fastapi import FastAPI
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/teleport")
async def get_teleport() -> RedirectResponse:
    return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")

これは RedirectResponseResponse のサブクラスであるため機能し、FastAPI はこの単純なケースを自動的に処理します。

無効な戻り値の型アノテーション

しかし、有効な Pydantic 型ではない任意のオブジェクト (例: データベースオブジェクト) を返し、関数内でそのようにアノテーションした場合、FastAPI はその型アノテーションから Pydantic レスポンスモデルを作成しようとして失敗します。

有効な Pydantic 型ではない型が1つ以上含まれる複数の型のユニオンがある場合も同様で、例えばこれは失敗します 💥

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal")
async def get_portal(teleport: bool = False) -> Response | dict:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal")
async def get_portal(teleport: bool = False) -> Union[Response, dict]:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}

...これは、型アノテーションが Pydantic 型ではなく、単一の Response クラスまたはサブクラスでもなく、Responsedict のユニオン (どちらか一方) であるため、失敗します。

レスポンスモデルを無効にする

上記の例に続き、FastAPI が実行するデフォルトのデータ検証、ドキュメント化、フィルタリングなどを行いたくない場合があります。

しかし、エディタや型チェッカー (例: mypy) のようなツールからのサポートを得るために、関数の戻り値の型アノテーションは保持したい場合があります。

この場合、response_model=None を設定することで、レスポンスモデルの生成を無効にできます。

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal", response_model=None)
async def get_portal(teleport: bool = False) -> Response | dict:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI, Response
from fastapi.responses import RedirectResponse

app = FastAPI()


@app.get("/portal", response_model=None)
async def get_portal(teleport: bool = False) -> Union[Response, dict]:
    if teleport:
        return RedirectResponse(url="https://www.youtube.com/watch?v=dQw4w9WgXcQ")
    return {"message": "Here's your interdimensional portal."}

これにより、FastAPIはレスポンスモデルの生成をスキップし、FastAPIアプリケーションに影響を与えることなく、必要な戻り値の型アノテーションを持つことができます。🤓

レスポンスモデルのエンコーディングパラメータ

応答モデルには、次のようなデフォルト値が含まれる場合があります。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
  • description: Union[str, None] = None (または Python 3.10 では str | None = None) は、デフォルトで None です。
  • tax: float = 10.5 は、デフォルトで 10.5 です。
  • tags: List[str] = [] は、デフォルトで空のリスト [] です。

ただし、実際に保存されていない場合は、結果から除外したい場合があります。

たとえば、NoSQLデータベースに多くのオプション属性を持つモデルがあるが、デフォルト値でいっぱいの非常に長いJSONレスポンスを送信したくない場合などです。

response_model_exclude_unset パラメータを使用する

パス操作デコレータのパラメータ response_model_exclude_unset=True を設定できます。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: list[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]
from typing import List, Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5
    tags: List[str] = []


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The bartenders", "price": 62, "tax": 20.2},
    "baz": {"name": "Baz", "description": None, "price": 50.2, "tax": 10.5, "tags": []},
}


@app.get("/items/{item_id}", response_model=Item, response_model_exclude_unset=True)
async def read_item(item_id: str):
    return items[item_id]

これにより、デフォルト値はレスポンスに含まれず、実際に設定された値のみが含まれます。

したがって、ID foo のアイテムに対してそのパス操作にリクエストを送信した場合、レスポンス (デフォルト値を除く) は次のようになります。

{
    "name": "Foo",
    "price": 50.2
}

情報

Pydantic v1 ではメソッドは .dict() と呼ばれていましたが、Pydantic v2 では非推奨 (ただし引き続きサポートされています) となり、.model_dump() に改名されました。

ここでの例は Pydantic v1 との互換性のために .dict() を使用していますが、Pydantic v2 を使用できる場合は代わりに .model_dump() を使用してください。

情報

FastAPI は、Pydantic モデルの .dict()その exclude_unset パラメータ を使用してこれを実現します。

情報

以下も使用できます。

  • response_model_exclude_defaults=True
  • response_model_exclude_none=True

Pydantic ドキュメントexclude_defaultsexclude_none の説明を参照してください。

デフォルト値を持つフィールドの値を持つデータ

しかし、データがID bar のアイテムのように、デフォルト値を持つモデルのフィールドの値を持っている場合、

{
    "name": "Bar",
    "description": "The bartenders",
    "price": 62,
    "tax": 20.2
}

それらはレスポンスに含まれます。

デフォルト値と同じ値を持つデータ

データがID baz のアイテムのように、デフォルト値と同じ値を持っている場合、

{
    "name": "Baz",
    "description": None,
    "price": 50.2,
    "tax": 10.5,
    "tags": []
}

FastAPI は (実際には Pydantic が) 賢く、descriptiontaxtags がデフォルト値と同じ値を持っているにもかかわらず、明示的に設定された (デフォルトから取得されたのではなく) と認識します。

そのため、JSONレスポンスに含まれます。

ヒント

デフォルト値は None だけでなく、何でもよいことに注意してください。

リスト ([])、float10.5 などです。

response_model_includeresponse_model_exclude

パス操作デコレータパラメータの response_model_includeresponse_model_exclude も使用できます。

これらは、含める (残りを省略する) または除外する (残りをすべて含める) 属性の名前を持つ strset を受け取ります。

これは、Pydantic モデルが1つだけで、出力から一部のデータを削除したい場合の簡単なショートカットとして使用できます。

ヒント

ただし、これらのパラメータを使用するよりも、複数のクラスを使用する上記のアイデアを使用することをお勧めします。

これは、response_model_includeresponse_model_exclude を使用して一部の属性を省略しても、アプリのOpenAPI (およびドキュメント) で生成されるJSON Schemaは、完全なモデルのものになるためです。

これは、同様に機能する response_model_by_alias にも当てはまります。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
    return items[item_id]
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include={"name", "description"},
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude={"tax"})
async def read_item_public_data(item_id: str):
    return items[item_id]

ヒント

構文 {"name", "description"} は、これら2つの値を持つ set を作成します。

これは set(["name", "description"]) と同等です。

set の代わりに list を使用する

set を使用するのを忘れて list または tuple を使用しても、FastAPI はそれを set に変換し、正しく動作します。

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: str | None = None
    price: float
    tax: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include=["name", "description"],
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
async def read_item_public_data(item_id: str):
    return items[item_id]
🤓 その他のバージョンとバリアント
from typing import Union

from fastapi import FastAPI
from pydantic import BaseModel

app = FastAPI()


class Item(BaseModel):
    name: str
    description: Union[str, None] = None
    price: float
    tax: float = 10.5


items = {
    "foo": {"name": "Foo", "price": 50.2},
    "bar": {"name": "Bar", "description": "The Bar fighters", "price": 62, "tax": 20.2},
    "baz": {
        "name": "Baz",
        "description": "There goes my baz",
        "price": 50.2,
        "tax": 10.5,
    },
}


@app.get(
    "/items/{item_id}/name",
    response_model=Item,
    response_model_include=["name", "description"],
)
async def read_item_name(item_id: str):
    return items[item_id]


@app.get("/items/{item_id}/public", response_model=Item, response_model_exclude=["tax"])
async def read_item_public_data(item_id: str):
    return items[item_id]

まとめ

応答モデルを定義し、特にプライベートデータをフィルタリングするために、パス操作デコレータのパラメータ response_model を使用してください。

明示的に設定された値のみを返すには、response_model_exclude_unset を使用します。