Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Conversation

@vvanglro
Copy link
Contributor

@vvanglro vvanglro commented Jun 20, 2023

@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
pydantic/pydantic#866

Related Issues:
#8394
#8853

Here is a MRE:

UPD YuriiMotov:

from fastapi import FastAPI
from fastapi.testclient import TestClient
from pydantic import BaseModel, Field

app = FastAPI()

class ResponseModel(BaseModel):
    code: int = 200
    message: str = Field(default_factory=lambda: "Successful operation.")

@app.get(
    "/response_model_has_default_factory_return_dict",
    response_model=ResponseModel,
)
async def response_model_has_default_factory_return_dict():
    return {"code": 200}


client = TestClient(app)

def test_response_model_has_default_factory_return_dict():
    response = client.get("/response_model_has_default_factory_return_dict")

    assert response.status_code == 200, response.text

    assert response.json()["code"] == 200
    assert response.json()["message"] == "Successful operation."

original code example in details

Details
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)

@tiangolo

This comment was marked as outdated.

@tiangolo
Copy link
Member

📝 Docs preview for commit c575414 at: https://649474bddaa2444d0ae2bad3--fastapi.netlify.app

@tiangolo tiangolo added bug Something isn't working p3 and removed investigate labels Jan 15, 2024
@vvanglro
Copy link
Contributor Author

@tiangolo I just resolved the conflict, can you take a look at it? Any plans to merge?

@alejsdev alejsdev self-assigned this Aug 31, 2024
@alejsdev
Copy link
Member

Hi @vvanglro, thank you for being so interested in contributing to FastAPI. We appreciate your effort and the time you have taken to submit this PR. We have a high volume of PRs and we're working hard to review and classify them. We'll review your PR soon 🙇‍♀️
We appreciate your patience as we managed the queue. Thanks!

Copy link
Member

@YuriiMotov YuriiMotov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

This issue is only relevant when working with Pydantic V1.

I simplified tests a bit.

@vvanglro, thanks for working on this!

tests/test_response_model_default_factory.py Outdated Show resolved Hide resolved
tests/test_response_model_default_factory.py Outdated Show resolved Hide resolved
tests/test_response_model_default_factory.py Outdated Show resolved Hide resolved
tests/test_response_model_default_factory.py Outdated Show resolved Hide resolved
tests/test_response_model_default_factory.py Outdated Show resolved Hide resolved
@YuriiMotov YuriiMotov changed the title fix: return dict response model default factory is not work ⚡️ Fix default_factory for response model field with Pydantic V1 Jul 25, 2025
@vvanglro
Copy link
Contributor Author

@YuriiMotov Everything seems to be in order. Let's merge.

Copy link
Member

@tiangolo tiangolo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice, thank you! 🍰

And thanks a lot @YuriiMotov for the work on this! ☕

@tiangolo tiangolo merged commit f1e6f97 into fastapi:master Sep 20, 2025
28 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working p3

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants

Morty Proxy This is a proxified and sanitized view of the page, visit original site.