]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🐛 Fix support for form values with empty strings interpreted as missing (`None` if...
authorad hoc <postma.marin@protonmail.com>
Tue, 2 Dec 2025 04:39:55 +0000 (05:39 +0100)
committerGitHub <noreply@github.com>
Tue, 2 Dec 2025 04:39:55 +0000 (05:39 +0100)
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Co-authored-by: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com>
Co-authored-by: Yurii Motov <yurii.motov.monte@gmail.com>
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
fastapi/dependencies/utils.py
tests/test_form_default.py [new file with mode: 0644]

index d43fa8a5163ec16b3c9beb4e8bca448cfb9a8674..0f25a3c3605dd73f499026f2c808dcbd0d37f7ee 100644 (file)
@@ -902,8 +902,9 @@ async def _extract_form_body(
             value = serialize_sequence_value(field=field, value=results)
         if value is not None:
             values[field.alias] = value
+    field_aliases = {field.alias for field in body_fields}
     for key, value in received_body.items():
-        if key not in values:
+        if key not in field_aliases:
             values[key] = value
     return values
 
diff --git a/tests/test_form_default.py b/tests/test_form_default.py
new file mode 100644 (file)
index 0000000..2a12049
--- /dev/null
@@ -0,0 +1,35 @@
+from typing import Optional
+
+from fastapi import FastAPI, File, Form
+from starlette.testclient import TestClient
+from typing_extensions import Annotated
+
+app = FastAPI()
+
+
+@app.post("/urlencoded")
+async def post_url_encoded(age: Annotated[Optional[int], Form()] = None):
+    return age
+
+
+@app.post("/multipart")
+async def post_multi_part(
+    age: Annotated[Optional[int], Form()] = None,
+    file: Annotated[Optional[bytes], File()] = None,
+):
+    return {"file": file, "age": age}
+
+
+client = TestClient(app)
+
+
+def test_form_default_url_encoded():
+    response = client.post("/urlencoded", data={"age": ""})
+    assert response.status_code == 200
+    assert response.text == "null"
+
+
+def test_form_default_multi_part():
+    response = client.post("/multipart", data={"age": ""})
+    assert response.status_code == 200
+    assert response.json() == {"file": None, "age": None}