mirror of https://github.com/tiangolo/fastapi.git
Using pydantic custom encoders (#21)
Add support for Pydantic custom JSON encoders.
This commit is contained in:
parent
02e53fde90
commit
32438c85f6
|
|
@ -12,12 +12,20 @@ def jsonable_encoder(
|
||||||
exclude: Set[str] = set(),
|
exclude: Set[str] = set(),
|
||||||
by_alias: bool = False,
|
by_alias: bool = False,
|
||||||
include_none: bool = True,
|
include_none: bool = True,
|
||||||
|
custom_encoder: dict = {},
|
||||||
) -> Any:
|
) -> Any:
|
||||||
if isinstance(obj, BaseModel):
|
if isinstance(obj, BaseModel):
|
||||||
return jsonable_encoder(
|
if not obj.Config.json_encoders:
|
||||||
obj.dict(include=include, exclude=exclude, by_alias=by_alias),
|
return jsonable_encoder(
|
||||||
include_none=include_none,
|
obj.dict(include=include, exclude=exclude, by_alias=by_alias),
|
||||||
)
|
include_none=include_none,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
return jsonable_encoder(
|
||||||
|
obj.dict(include=include, exclude=exclude, by_alias=by_alias),
|
||||||
|
include_none=include_none,
|
||||||
|
custom_encoder=obj.Config.json_encoders,
|
||||||
|
)
|
||||||
if isinstance(obj, Enum):
|
if isinstance(obj, Enum):
|
||||||
return obj.value
|
return obj.value
|
||||||
if isinstance(obj, (str, int, float, type(None))):
|
if isinstance(obj, (str, int, float, type(None))):
|
||||||
|
|
@ -25,8 +33,16 @@ def jsonable_encoder(
|
||||||
if isinstance(obj, dict):
|
if isinstance(obj, dict):
|
||||||
return {
|
return {
|
||||||
jsonable_encoder(
|
jsonable_encoder(
|
||||||
key, by_alias=by_alias, include_none=include_none
|
key,
|
||||||
): jsonable_encoder(value, by_alias=by_alias, include_none=include_none)
|
by_alias=by_alias,
|
||||||
|
include_none=include_none,
|
||||||
|
custom_encoder=custom_encoder,
|
||||||
|
): jsonable_encoder(
|
||||||
|
value,
|
||||||
|
by_alias=by_alias,
|
||||||
|
include_none=include_none,
|
||||||
|
custom_encoder=custom_encoder,
|
||||||
|
)
|
||||||
for key, value in obj.items()
|
for key, value in obj.items()
|
||||||
if value is not None or include_none
|
if value is not None or include_none
|
||||||
}
|
}
|
||||||
|
|
@ -38,12 +54,16 @@ def jsonable_encoder(
|
||||||
exclude=exclude,
|
exclude=exclude,
|
||||||
by_alias=by_alias,
|
by_alias=by_alias,
|
||||||
include_none=include_none,
|
include_none=include_none,
|
||||||
|
custom_encoder=custom_encoder,
|
||||||
)
|
)
|
||||||
for item in obj
|
for item in obj
|
||||||
]
|
]
|
||||||
errors = []
|
errors = []
|
||||||
try:
|
try:
|
||||||
encoder = ENCODERS_BY_TYPE[type(obj)]
|
if custom_encoder and type(obj) in custom_encoder:
|
||||||
|
encoder = custom_encoder[type(obj)]
|
||||||
|
else:
|
||||||
|
encoder = ENCODERS_BY_TYPE[type(obj)]
|
||||||
return encoder(obj)
|
return encoder(obj)
|
||||||
except KeyError as e:
|
except KeyError as e:
|
||||||
errors.append(e)
|
errors.append(e)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,35 @@
|
||||||
|
import json
|
||||||
|
from datetime import datetime, timezone
|
||||||
|
|
||||||
|
from fastapi import FastAPI
|
||||||
|
from pydantic import BaseModel
|
||||||
|
from starlette.testclient import TestClient
|
||||||
|
|
||||||
|
|
||||||
|
class ModelWithDatetimeField(BaseModel):
|
||||||
|
dt_field: datetime
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
json_encoders = {
|
||||||
|
datetime: lambda dt: dt.replace(
|
||||||
|
microsecond=0, tzinfo=timezone.utc
|
||||||
|
).isoformat()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
app = FastAPI()
|
||||||
|
model = ModelWithDatetimeField(dt_field=datetime.utcnow())
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/model", response_model=ModelWithDatetimeField)
|
||||||
|
def get_model():
|
||||||
|
return model
|
||||||
|
|
||||||
|
|
||||||
|
client = TestClient(app)
|
||||||
|
|
||||||
|
|
||||||
|
def test_dt():
|
||||||
|
with client:
|
||||||
|
response = client.get("/model")
|
||||||
|
assert json.loads(model.json()) == response.json()
|
||||||
Loading…
Reference in New Issue