fix(api): honor DELETE JSON body in model_validate (#41288)

This commit is contained in:
lei_lei 2026-08-26 06:38:13 +00:00 committed by GitHub
parent c563528a2d
commit 119e6af2a9
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 48 additions and 2 deletions

View File

@ -661,7 +661,8 @@ def model_validate[T, M: BaseModel, **P, R](
"""Validate request data and inject the model instance as the first arg after self.
Source is determined by HTTP method:
GET/DELETE -> request.args
GET -> request.args
DELETE -> request.args, falling back to JSON body when the query string is empty
POST/PUT/PATCH -> JSON body
"""
@ -670,8 +671,10 @@ def model_validate[T, M: BaseModel, **P, R](
) -> Callable[Concatenate[T, P], R]:
@wraps(view)
def wrapper(self: T, *args: P.args, **kwargs: P.kwargs) -> R:
if request.method in ("GET", "DELETE"):
if request.method == "GET":
raw = request.args.to_dict(flat=True)
elif request.method == "DELETE":
raw = request.args.to_dict(flat=True) or (request.get_json(silent=True) or {})
else:
raw = request.get_json(silent=True) or {}

View File

@ -670,6 +670,49 @@ class TestModelValidationInjection:
assert payload == self.Payload(name="alpha", count=2)
def test_should_inject_delete_payload_from_query_params(self):
app = Flask(__name__)
class Handler:
@model_validate(TestModelValidationInjection.Payload)
def delete(self, payload: TestModelValidationInjection.Payload):
return payload
with app.test_request_context("/items?name=alpha&count=2", method="DELETE"):
payload = Handler().delete()
assert payload == self.Payload(name="alpha", count=2)
def test_should_inject_delete_payload_from_json_body(self):
app = Flask(__name__)
class Handler:
@model_validate(TestModelValidationInjection.Payload)
def delete(self, payload: TestModelValidationInjection.Payload):
return payload
with app.test_request_context("/items", method="DELETE", json={"name": "alpha", "count": 2}):
payload = Handler().delete()
assert payload == self.Payload(name="alpha", count=2)
def test_should_prefer_delete_query_params_over_json_body(self):
app = Flask(__name__)
class Handler:
@model_validate(TestModelValidationInjection.Payload)
def delete(self, payload: TestModelValidationInjection.Payload):
return payload
with app.test_request_context(
"/items?name=alpha&count=2",
method="DELETE",
json={"name": "beta", "count": 9},
):
payload = Handler().delete()
assert payload == self.Payload(name="alpha", count=2)
def test_should_raise_unprocessable_entity_for_invalid_payload(self):
app = Flask(__name__)