fastapi
fastapi copied to clipboard
fix: return dict response model default factory is not work
@tiangolo Hi, When returning a dictionary, if there is a default_factory
in the model, it will not take effect, and the return value is None. Normal if returned as a model.
The default_factory
added by pydantic in version 1.5, I checked the documentation and it seems that it is still in the beta stage, so is this the reason does not support default_factory
or is there another reason? But I think the consistency of the two return methods should be kept.
Related Documentation Links: https://docs.pydantic.dev/latest/usage/models/#field-with-dynamic-default-value https://github.com/pydantic/pydantic/issues/866
Related Issues: https://github.com/tiangolo/fastapi/discussions/8394 https://github.com/tiangolo/fastapi/discussions/8853
Here is a minimal reproducible example:
from functools import partial
from typing import Optional
import fastapi
from fastapi import Request
from pydantic import BaseModel, Field
from starlette.middleware.base import BaseHTTPMiddleware, RequestResponseEndpoint
from starlette.responses import Response
app = fastapi.FastAPI()
TRANSLATIONS = {
"zh_CN": {"操作成功": "操作成功"},
"en_US": {"操作成功": "Successful operation."},
}
translations = TRANSLATIONS.get("zh_CN")
def set_locale(locale: str):
global translations
translations = TRANSLATIONS.get(locale) or TRANSLATIONS.get("zh_CN")
def _(msg: str):
return translations.get(msg)
class InternationalizationMiddleware(BaseHTTPMiddleware):
async def dispatch(
self, request: Request, call_next: RequestResponseEndpoint
) -> Response:
lang_code: Optional[str] = request.headers.get("Accept-Language", None)
set_locale(lang_code)
response: _StreamingResponse = await call_next(request) # type: ignore
return response
app.add_middleware(InternationalizationMiddleware)
class ResponseModel(BaseModel):
code: int = 200
message: str = Field(default_factory=partial(_, msg="操作成功"))
@app.get('/not_work', response_model=ResponseModel)
async def func():
return {"code": 200}
@app.get('/work', response_model=ResponseModel)
async def func():
return ResponseModel()
if __name__ == '__main__':
import uvicorn
uvicorn.run(app, port=8089)