8000 ⚡️ Improve performance in request body parsing with a cache for inter… · fastapi/fastapi@b0eedbb · GitHub
[go: up one dir, main page]

Skip to content

Commit b0eedbb

Browse files
authored
⚡️ Improve performance in request body parsing with a cache for internal model fields (#12184)
1 parent 7445118 commit b0eedbb

File tree

3 files changed

+24
-2
lines changed

3 files changed

+24
-2
lines changed

fastapi/_compat.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
from copy import copy
33
from dataclasses import dataclass, is_dataclass
44
from enum import Enum
5+
from functools import lru_cache
56
from typing import (
67
Any,
78
Callable,
@@ -649,3 +650,8 @@ def is_uploadfile_sequence_annotation(annotation: Any) -> bool:
649650
is_uploadfile_or_nonable_uploadfile_annotation(sub_annotation)
650651
for sub_annotation in get_args(annotation)
651652
)
653+
654+
655+
@lru_cache
656+
def get_cached_model_fields(model: Type[BaseModel]) -> List[ModelField]:
657+
return get_model_fields(model)

fastapi/dependencies/utils.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,8 @@
3232
evaluate_forwardref,
3333
field_annotation_is_scalar,
3434
get_annotation_from_field_info,
35+
get_cached_model_fields,
3536
get_missing_field_error,
36-
get_model_fields,
3737
is_bytes_field,
3838
is_bytes_sequence_field,
3939
is_scalar_field,
@@ -810,7 +810,7 @@ async def request_body_to_args(
810810
fields_to_extract: List[ModelField] = body_fields
811811

812812
if single_not_embedded_field and lenient_issubclass(first_field.type_, BaseModel):
813-
fields_to_extract = get_model_fields(first_field.type_)
813+
fields_to_extract = get_cached_model_fields(first_field.type_)
814814

815815
if isinstance(received_body, FormData):
816816
body_to_process = await _extract_form_body(fields_to_extract, received_body)

tests/test_compat.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
ModelField,
66
Undefined,
77
_get_model_config,
8+
get_cached_model_fields,
89
get_model_fields,
910
is_bytes_sequence_annotation,
1011
is_scalar_field,
@@ -102,3 +103,18 @@ class Model(BaseModel):
102103

103104
fields = get_model_fields(Model)
104105
assert not is_scalar_field(fields[0])
106+
107+
108+
def test_get_model_fields_cached():
109+
class Model(BaseModel):
110+
foo: str
111+
112+
non_cached_fields = get_model_fields(Model)
113+
non_cached_fields2 = get_model_fields(Model)
114+
cached_fields = get_cached_model_fields(Model)
115+
cached_fields2 = get_cached_model_fields(Model)
116+
for f1, f2 in zip(cached_fields, cached_fields2):
117+
assert f1 is f2
118+
119+
assert non_cached_fields is not non_cached_fields2
120+
assert cached_fields is cached_fields2

0 commit comments

Comments
 (0)
0