Skip to content

Commit fd2a39d

Browse files
committed
Preserve Field constraints in PatchDict
1 parent 31c1275 commit fd2a39d

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

ninja/patch_dict.py

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -45,15 +45,20 @@ def get_schema_annotations(schema_cls: Type[Any]) -> Dict[str, Any]:
4545
return annotations
4646

4747

48-
def create_patch_schema(schema_cls: Type[Any]) -> Type[ModelToDict]:
48+
def create_patch_schema(schema_cls: Type[BaseModel]) -> Type[ModelToDict]:
4949
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]
50+
values: Dict[str, Any] = {}
51+
annotations = {}
52+
53+
for name, field in schema_cls.model_fields.items():
54+
annotation = schema_annotations[name]
55+
if is_optional_type(annotation):
56+
continue
57+
patch_field = field._copy()
58+
patch_field.default = None
59+
patch_field.default_factory = None
60+
values[name] = patch_field
61+
annotations[name] = Optional[annotation]
5762
values["__annotations__"] = annotations
5863
OptionalSchema = type(f"{schema_cls.__name__}Patch", (schema_cls,), values)
5964

tests/test_patch_dict.py

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import pytest
44

5-
from ninja import NinjaAPI, Schema
5+
from ninja import Field, NinjaAPI, Schema
66
from ninja.patch_dict import PatchDict
77
from ninja.testing import TestClient
88

@@ -15,6 +15,7 @@ class SomeSchema(Schema):
1515
name: str
1616
age: int
1717
category: Optional[str] = None
18+
identifier: str = Field(max_length=32)
1819

1920

2021
class OtherSchema(SomeSchema):
@@ -47,6 +48,11 @@ def test_patch_calls(input: dict, output: dict):
4748
assert response.json() == {"payload": output, "type": "<class 'dict'>"}
4849

4950

51+
def test_patch_calls_bad_request():
52+
response = client.patch("/patch", json={"identifier": "0" * 100})
53+
assert response.status_code == 422
54+
55+
5056
def test_schema():
5157
"Checking that json schema properties are all optional"
5258
schema = api.get_openapi_schema()
@@ -66,6 +72,13 @@ def test_schema():
6672
"anyOf": [{"type": "string"}, {"type": "null"}],
6773
"title": "Category",
6874
},
75+
"identifier": {
76+
"anyOf": [
77+
{"maxLength": 32, "type": "string"},
78+
{"type": "null"},
79+
],
80+
"title": "Identifier",
81+
},
6982
},
7083
}
7184

@@ -93,6 +106,13 @@ def test_inherited_schema():
93106
"anyOf": [{"type": "integer"}, {"type": "null"}],
94107
"title": "Age",
95108
},
109+
"identifier": {
110+
"anyOf": [
111+
{"maxLength": 32, "type": "string"},
112+
{"type": "null"},
113+
],
114+
"title": "Identifier",
115+
},
96116
"other": {
97117
"anyOf": [{"type": "string"}, {"type": "null"}],
98118
"title": "Other",

0 commit comments

Comments
 (0)