From 6cf40df24d1d199fd25d034fc87fcae284fc23a2 Mon Sep 17 00:00:00 2001 From: Motov Yurii <109919500+YuriiMotov@users.noreply.github.com> Date: Tue, 2 Dec 2025 05:49:32 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=90=9B=20Fix=20parsing=20extra=20`Form`?= =?UTF-8?q?=20parameter=20list=20(#14303)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Sebastián Ramírez --- fastapi/dependencies/utils.py | 8 ++++-- tests/test_forms_single_model.py | 47 ++++++++++++++++++++++++++++++++ 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/fastapi/dependencies/utils.py b/fastapi/dependencies/utils.py index 0f25a3c36..2b2e6c5af 100644 --- a/fastapi/dependencies/utils.py +++ b/fastapi/dependencies/utils.py @@ -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 diff --git a/tests/test_forms_single_model.py b/tests/test_forms_single_model.py index 880ab3820..1db63f021 100644 --- a/tests/test_forms_single_model.py +++ b/tests/test_forms_single_model.py @@ -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"], + }