mirror of https://github.com/tiangolo/fastapi.git
Merge 39a50627e1 into 0127069d47
This commit is contained in:
commit
dd04e1ce13
|
|
@ -751,7 +751,11 @@ def _is_json_field(field: ModelField) -> bool:
|
|||
|
||||
|
||||
def _get_multidict_value(
|
||||
field: ModelField, values: Mapping[str, Any], alias: str | None = None
|
||||
field: ModelField,
|
||||
values: Mapping[str, Any],
|
||||
alias: str | None = None,
|
||||
*,
|
||||
default_on_missing: bool = True,
|
||||
) -> Any:
|
||||
alias = alias or get_validation_alias(field)
|
||||
if (
|
||||
|
|
@ -776,8 +780,9 @@ def _get_multidict_value(
|
|||
):
|
||||
if field.field_info.is_required():
|
||||
return
|
||||
else:
|
||||
if default_on_missing:
|
||||
return deepcopy(field.default)
|
||||
return None
|
||||
return value
|
||||
|
||||
|
||||
|
|
@ -961,6 +966,7 @@ async def request_body_to_args(
|
|||
body_to_process = received_body
|
||||
|
||||
fields_to_extract: list[ModelField] = body_fields
|
||||
provided_form_fields: set[str] | None = None
|
||||
|
||||
if (
|
||||
single_not_embedded_field
|
||||
|
|
@ -968,6 +974,17 @@ async def request_body_to_args(
|
|||
and isinstance(received_body, FormData)
|
||||
):
|
||||
fields_to_extract = get_cached_model_fields(first_field.field_info.annotation)
|
||||
provided_form_fields = {
|
||||
field.name
|
||||
for field in fields_to_extract
|
||||
if _get_multidict_value(
|
||||
field,
|
||||
received_body,
|
||||
alias=get_validation_alias(field),
|
||||
default_on_missing=False,
|
||||
)
|
||||
is not None
|
||||
}
|
||||
|
||||
if isinstance(received_body, FormData):
|
||||
body_to_process = await _extract_form_body(fields_to_extract, received_body)
|
||||
|
|
@ -977,6 +994,12 @@ async def request_body_to_args(
|
|||
v_, errors_ = _validate_value_with_model_field(
|
||||
field=first_field, value=body_to_process, values=values, loc=loc
|
||||
)
|
||||
if (
|
||||
provided_form_fields is not None
|
||||
and not errors_
|
||||
and isinstance(v_, BaseModel)
|
||||
):
|
||||
v_.__pydantic_fields_set__ = provided_form_fields
|
||||
return {first_field.name: v_}, errors_
|
||||
for field in body_fields:
|
||||
loc = ("body", get_validation_alias(field))
|
||||
|
|
|
|||
|
|
@ -31,6 +31,20 @@ def post_form_extra_allow(params: Annotated[FormModelExtraAllow, Form()]):
|
|||
return params
|
||||
|
||||
|
||||
class FormModelFieldsSet(BaseModel):
|
||||
field_1: bool = True
|
||||
|
||||
|
||||
@app.post("/form-model-fields-set/")
|
||||
def post_form_model_fields_set(model: Annotated[FormModelFieldsSet, Form()]):
|
||||
return {"fields_set": sorted(model.model_fields_set)}
|
||||
|
||||
|
||||
@app.post("/body-model-fields-set/")
|
||||
def post_body_model_fields_set(model: FormModelFieldsSet):
|
||||
return {"fields_set": sorted(model.model_fields_set)}
|
||||
|
||||
|
||||
client = TestClient(app)
|
||||
|
||||
|
||||
|
|
@ -139,3 +153,14 @@ def test_extra_param_list():
|
|||
"param": "123",
|
||||
"extra_params": ["456", "789"],
|
||||
}
|
||||
|
||||
|
||||
def test_default_field_not_marked_as_set_for_form_model():
|
||||
body_response = client.post("/body-model-fields-set/", json={})
|
||||
form_response = client.post("/form-model-fields-set/", data={})
|
||||
|
||||
assert body_response.status_code == 200, body_response.text
|
||||
assert form_response.status_code == 200, form_response.text
|
||||
|
||||
assert body_response.json() == {"fields_set": []}
|
||||
assert form_response.json() == {"fields_set": []}
|
||||
|
|
|
|||
Loading…
Reference in New Issue