Skip to content

Commit

Permalink
forms.SchemaField.to_python(): check if value already has a target ty…
Browse files Browse the repository at this point in the history
…pe (#45)

* Skip conversion if a value already have a target type

* Try to parse non-string python objects into form field schema

* Parse byte values as json as well

---------

Co-authored-by: Savva Surenkov <[email protected]>
  • Loading branch information
alexey-sveshnikov and surenkov authored Jan 30, 2024
1 parent 24e37c5 commit 048d8bd
Show file tree
Hide file tree
Showing 3 changed files with 35 additions and 18 deletions.
16 changes: 10 additions & 6 deletions django_pydantic_field/v2/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,22 @@ def to_python(self, value: ty.Any) -> ty.Any:
return value
if value in self.empty_values:
return None
elif isinstance(value, JSONString):
return value

try:
converted = self.adapter.validate_json(value)
if not isinstance(value, (str, bytes)):
# The form data may contain python objects for some cases (e.g. using django-constance).
value = self.adapter.validate_python(value)
elif not isinstance(value, JSONString):
# Otherwise, try to parse incoming JSON according to the schema.
value = self.adapter.validate_json(value)
except pydantic.ValidationError as exc:
error_params = {"value": value, "title": exc.title, "detail": exc.json(), "errors": exc.errors()}
raise ValidationError(self.error_messages["schema_error"], code="invalid", params=error_params) from exc

if isinstance(converted, str):
return JSONString(converted)
if isinstance(value, str):
value = JSONString(value)

return converted
return value

def prepare_value(self, value):
if isinstance(value, InvalidJSONInput):
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "django-pydantic-field"
version = "0.3.1"
version = "0.3.2-beta1"
description = "Django JSONField with Pydantic models as a Schema"
readme = "README.md"
license = { file = "LICENSE" }
Expand Down
35 changes: 24 additions & 11 deletions tests/v2/test_forms.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import typing as ty
from datetime import date

import django
import pytest
Expand All @@ -16,11 +17,20 @@ class SampleForm(Form):
field = forms.SchemaField(ty.ForwardRef("SampleSchema"))


def test_form_schema_field():
@pytest.mark.parametrize(
"raw_data, clean_data",
[
('{"stub_str": "abc", "stub_list": ["1970-01-01"]}', {"stub_str": "abc", "stub_list": ["1970-01-01"]}),
(b'{"stub_str": "abc", "stub_list": ["1970-01-01"]}', {"stub_str": "abc", "stub_list": ["1970-01-01"]}),
({"stub_str": "abc", "stub_list": ["1970-01-01"]}, {"stub_str": "abc", "stub_list": ["1970-01-01"]}),
(InnerSchema(stub_str="abc", stub_list=[date(1970, 1, 1)]), {"stub_str": "abc", "stub_list": ["1970-01-01"]}),
],
)
def test_form_schema_field(raw_data, clean_data):
field = forms.SchemaField(InnerSchema)

cleaned_data = field.clean('{"stub_str": "abc", "stub_list": ["1970-01-01"]}')
assert cleaned_data == InnerSchema.model_validate({"stub_str": "abc", "stub_list": ["1970-01-01"]})
cleaned_data = field.clean(raw_data)
assert cleaned_data == InnerSchema.model_validate(clean_data)


def test_empty_form_values():
Expand Down Expand Up @@ -87,14 +97,17 @@ def test_forwardref_model_formfield():
assert cleaned_data["annotated_field"] == SampleSchema(field=2)


@pytest.mark.parametrize("export_kwargs", [
{"include": {"stub_str", "stub_int"}},
{"exclude": {"stub_list"}},
{"exclude_unset": True},
{"exclude_defaults": True},
{"exclude_none": True},
{"by_alias": True},
])
@pytest.mark.parametrize(
"export_kwargs",
[
{"include": {"stub_str", "stub_int"}},
{"exclude": {"stub_list"}},
{"exclude_unset": True},
{"exclude_defaults": True},
{"exclude_none": True},
{"by_alias": True},
],
)
def test_form_field_export_kwargs(export_kwargs):
field = forms.SchemaField(InnerSchema, required=False, **export_kwargs)
value = InnerSchema.model_validate({"stub_str": "abc", "stub_list": ["1970-01-01"]})
Expand Down

0 comments on commit 048d8bd

Please sign in to comment.