]> git.ipfire.org Git - thirdparty/fastapi/fastapi.git/commitdiff
🐛 Fix parsing extra `Form` parameter list (#14303)
authorMotov Yurii <109919500+YuriiMotov@users.noreply.github.com>
Tue, 2 Dec 2025 04:49:32 +0000 (05:49 +0100)
committerGitHub <noreply@github.com>
Tue, 2 Dec 2025 04:49:32 +0000 (05:49 +0100)
Co-authored-by: Sebastián Ramírez <tiangolo@gmail.com>
fastapi/dependencies/utils.py
tests/test_forms_single_model.py

index 0f25a3c3605dd73f499026f2c808dcbd0d37f7ee..2b2e6c5af97f74190aeca9d9111ff27139ce6c9a 100644 (file)
@@ -903,9 +903,13 @@ async def _extract_form_body(
         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():
+    for key in received_body.keys():
         if key not in field_aliases:
-            values[key] = value
+            param_values = received_body.getlist(key)
+            if len(param_values) == 1:
+                values[key] = param_values[0]
+            else:
+                values[key] = param_values
     return values
 
 
index 880ab3820077229ce43c7c6a62929a79bfcea033..1db63f02148e3c7d20b6d54bf90b6c7bc1a63734 100644 (file)
@@ -2,6 +2,7 @@ from typing import List, Optional
 
 from dirty_equals import IsDict
 from fastapi import FastAPI, Form
+from fastapi._compat import PYDANTIC_V2
 from fastapi.testclient import TestClient
 from pydantic import BaseModel, Field
 from typing_extensions import Annotated
@@ -17,11 +18,27 @@ class FormModel(BaseModel):
     alias_with: str = Field(alias="with", default="nothing")
 
 
+class FormModelExtraAllow(BaseModel):
+    param: str
+
+    if PYDANTIC_V2:
+        model_config = {"extra": "allow"}
+    else:
+
+        class Config:
+            extra = "allow"
+
+
 @app.post("/form/")
 def post_form(user: Annotated[FormModel, Form()]):
     return user
 
 
+@app.post("/form-extra-allow/")
+def post_form_extra_allow(params: Annotated[FormModelExtraAllow, Form()]):
+    return params
+
+
 client = TestClient(app)
 
 
@@ -131,3 +148,33 @@ def test_no_data():
             ]
         }
     )
+
+
+def test_extra_param_single():
+    response = client.post(
+        "/form-extra-allow/",
+        data={
+            "param": "123",
+            "extra_param": "456",
+        },
+    )
+    assert response.status_code == 200, response.text
+    assert response.json() == {
+        "param": "123",
+        "extra_param": "456",
+    }
+
+
+def test_extra_param_list():
+    response = client.post(
+        "/form-extra-allow/",
+        data={
+            "param": "123",
+            "extra_params": ["456", "789"],
+        },
+    )
+    assert response.status_code == 200, response.text
+    assert response.json() == {
+        "param": "123",
+        "extra_params": ["456", "789"],
+    }