diff --git a/README.md b/README.md index 892dbc0..0103401 100644 --- a/README.md +++ b/README.md @@ -368,8 +368,57 @@ In short, GIL allows only one thread to work at a time, which makes it useless f 2. https://stackoverflow.com/questions/65342833/fastapi-uploadfile-is-slow-compared-to-flask 3. https://stackoverflow.com/questions/71516140/fastapi-runs-api-calls-in-serial-instead-of-parallel-fashion -### 9. Custom base model model from day 0, -convert datetime to common standard +### 9. Custom base model from day 0. +Having a controllable global pydantic base model allows us to customize all the models within the app. +For example, we could have a standard datetime format or add a super method for all subclasses of the base model. +```python +from datetime import datetime +from zoneinfo import ZoneInfo + +import orjson +from fastapi.encoders import jsonable_encoder +from pydantic import BaseModel, root_validator + + +def orjson_dumps(v, *, default): + # orjson.dumps returns bytes, to match standard json.dumps we need to decode + return orjson.dumps(v, default=default).decode() + + +def convert_datetime_to_gmt(dt: datetime) -> str: + if not dt.tzinfo: + dt = dt.replace(tzinfo=ZoneInfo("UTC")) + + return dt.strftime("%Y-%m-%dT%H:%M:%S%z") + + +class ORJSONModel(BaseModel): + class Config: + json_loads = orjson.loads + json_dumps = orjson_dumps + json_encoders = {datetime: convert_datetime_to_gmt} # method for customer JSON encoding of datetime fields + + @root_validator() + def set_null_microseconds(cls, data: dict) -> dict: + """Drops microseconds in all the datetime field values.""" + datetime_fields = { + k: v.replace(microsecond=0) + for k, v in data.items() + if isinstance(k, datetime) + } + + return {**data, **datetime_fields} + + def serializable_dict(self, **kwargs): + """Return a dict which contains only serializable fields.""" + default_dict = super().dict(**kwargs) + + return jsonable_encoder(default_dict) +``` +In the example above we have decided to make a global base model which: +- uses [orjson](https://github.com/ijl/orjson) to serialize data +- drops microseconds to 0 in all date formats +- serializes all datetime fields to standard format with explicit timezone ### 10. Docs 1. Unless your API is public, hide docs by default. Show it explicitly on the selected envs only. ```python