diff --git a/fastapi/encoders.py b/fastapi/encoders.py index c9f882d2ba..871188e33e 100644 --- a/fastapi/encoders.py +++ b/fastapi/encoders.py @@ -242,7 +242,7 @@ def jsonable_encoder( exclude = set(exclude) # type: ignore[assignment] # ty: ignore[invalid-assignment] if isinstance(obj, BaseModel): obj_dict = obj.model_dump( - mode="json", + mode="python" if custom_encoder else "json", include=include, exclude=exclude, by_alias=by_alias, @@ -254,6 +254,7 @@ def jsonable_encoder( obj_dict, exclude_none=exclude_none, exclude_defaults=exclude_defaults, + custom_encoder=custom_encoder, sqlalchemy_safe=sqlalchemy_safe, ) if dataclasses.is_dataclass(obj): diff --git a/tests/test_jsonable_encoder.py b/tests/test_jsonable_encoder.py index c23a9e5d79..d39033a8f6 100644 --- a/tests/test_jsonable_encoder.py +++ b/tests/test_jsonable_encoder.py @@ -12,7 +12,7 @@ import pytest from fastapi._compat import Undefined from fastapi.encoders import jsonable_encoder from fastapi.exceptions import PydanticV1NotSupportedError -from pydantic import BaseModel, Field, ValidationError +from pydantic import BaseModel, ConfigDict, Field, ValidationError class Person: @@ -225,6 +225,21 @@ def test_custom_encoders(): assert encoded_instance2["dt_field"] == instance["dt_field"].isoformat() +def test_custom_encoder_model_field(): + class CustomValue: + pass + + class ModelWithCustomValue(BaseModel): + model_config = ConfigDict(arbitrary_types_allowed=True) + + value: CustomValue + + assert jsonable_encoder( + ModelWithCustomValue(value=CustomValue()), + custom_encoder={CustomValue: lambda _: "encoded"}, + ) == {"value": "encoded"} + + def test_custom_enum_encoders(): def custom_enum_encoder(v: Enum): return v.value.lower()