1+ import copy
12from typing import (
23 TYPE_CHECKING ,
34 Any ,
910)
1011
1112from pydantic import BaseModel
13+ from pydantic .fields import FieldInfo
1214from pydantic_core import core_schema
1315
1416from ninja import Body
1517from ninja .orm import ModelSchema
1618from ninja .schema import Schema
1719from ninja .utils import is_optional_type
1820
21+ try :
22+ copy_field_info = FieldInfo ._copy
23+ except AttributeError :
24+ # Fallback for Pydantic<2.12.0
25+ copy_field_info = copy .copy
26+
1927
2028class ModelToDict (dict ):
2129 _wrapped_model : Any = None
@@ -45,15 +53,20 @@ def get_schema_annotations(schema_cls: Type[Any]) -> Dict[str, Any]:
4553 return annotations
4654
4755
48- def create_patch_schema (schema_cls : Type [Any ]) -> Type [ModelToDict ]:
56+ def create_patch_schema (schema_cls : Type [BaseModel ]) -> Type [ModelToDict ]:
4957 schema_annotations = get_schema_annotations (schema_cls )
50- values , annotations = {}, {}
51- # assert False, f"{schema_cls} - {schema_cls.model_fields}"
52- for f in schema_cls .model_fields .keys ():
53- t = schema_annotations [f ]
54- if not is_optional_type (t ):
55- values [f ] = getattr (schema_cls , f , None )
56- annotations [f ] = Optional [t ]
58+ values : Dict [str , Any ] = {}
59+ annotations = {}
60+
61+ for name , field in schema_cls .model_fields .items ():
62+ annotation = schema_annotations [name ]
63+ if is_optional_type (annotation ):
64+ continue
65+ patch_field = copy_field_info (field )
66+ patch_field .default = None
67+ patch_field .default_factory = None
68+ values [name ] = patch_field
69+ annotations [name ] = Optional [annotation ]
5770 values ["__annotations__" ] = annotations
5871 OptionalSchema = type (f"{ schema_cls .__name__ } Patch" , (schema_cls ,), values )
5972
@@ -65,7 +78,7 @@ class OptionalDictSchema(ModelToDict):
6578
6679
6780class PatchDictUtil :
68- def __getitem__ (self , schema_cls : Any ) -> Any :
81+ def __getitem__ (self , schema_cls : Type [ BaseModel ] ) -> Any :
6982 new_cls = create_patch_schema (schema_cls )
7083 return Body [new_cls ] # type: ignore
7184
0 commit comments