mirror of
https://github.com/kennethreitz/pydantic.git
synced 2026-06-05 23:00:18 +00:00
This reverts commit b42fae081c.
This commit is contained in:
@@ -1 +0,0 @@
|
||||
add `use_nested_encoders` keyword argument to `BaseModel.json` to allow encoding nested subclasses with encoders specified in the inner classes
|
||||
@@ -1,41 +0,0 @@
|
||||
from datetime import datetime, timedelta
|
||||
from pydantic import BaseModel
|
||||
from pydantic.json import timedelta_isoformat
|
||||
|
||||
|
||||
class CustomChildModel(BaseModel):
|
||||
dt: datetime
|
||||
diff: timedelta
|
||||
|
||||
class Config:
|
||||
json_encoders = {
|
||||
datetime: lambda v: v.timestamp(),
|
||||
timedelta: timedelta_isoformat,
|
||||
}
|
||||
|
||||
|
||||
class ParentModel(BaseModel):
|
||||
diff: timedelta
|
||||
child: CustomChildModel
|
||||
|
||||
class Config:
|
||||
json_encoders = {
|
||||
timedelta: lambda v: v.total_seconds(),
|
||||
CustomChildModel: lambda _: 'using parent encoder',
|
||||
}
|
||||
|
||||
|
||||
child = CustomChildModel(dt=datetime(2032, 6, 1), diff=timedelta(hours=100))
|
||||
parent = ParentModel(diff=timedelta(hours=3), child=child)
|
||||
|
||||
# default encoder uses total_seconds() for diff
|
||||
print(parent.json())
|
||||
|
||||
# nested encoder uses isoformat
|
||||
print(parent.json(use_nested_encoders=True))
|
||||
|
||||
# turning off models_as_dict only uses the top-level formatter, however
|
||||
|
||||
print(parent.json(models_as_dict=False, use_nested_encoders=True))
|
||||
|
||||
print(parent.json(models_as_dict=False, use_nested_encoders=False))
|
||||
@@ -118,20 +118,6 @@ In case of forward references, you can use a string with the class name instead
|
||||
```
|
||||
_(This script is complete, it should run "as is")_
|
||||
|
||||
### Nested serialisation of other models
|
||||
|
||||
By default, models that contain other models are serialised using the `json_encoders` functions of the
|
||||
parent or container class.
|
||||
However, you may want to nest classes in a modular fashion, including their `json_encoders`.
|
||||
In this case, call `json(use_nested_encoders=True)`.
|
||||
`use_nested_encoders` has no effect when `models_as_dict=False`, as the classes of the models
|
||||
are expected to be defined in the top-level `json_encoders`.
|
||||
|
||||
```py
|
||||
{!.tmp_examples/exporting_models_json_nested_encoders.py!}
|
||||
```
|
||||
_(This script is complete, it should run "as is")_
|
||||
|
||||
### Serialising subclasses
|
||||
|
||||
!!! note
|
||||
|
||||
@@ -427,7 +427,6 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
|
||||
exclude_unset: bool = False,
|
||||
exclude_defaults: bool = False,
|
||||
exclude_none: bool = False,
|
||||
encode_as_json: bool = False,
|
||||
) -> 'DictStrAny':
|
||||
"""
|
||||
Generate a dictionary representation of the model, optionally specifying which fields to include or exclude.
|
||||
@@ -449,7 +448,6 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
|
||||
exclude_unset=exclude_unset,
|
||||
exclude_defaults=exclude_defaults,
|
||||
exclude_none=exclude_none,
|
||||
encode_as_json=encode_as_json,
|
||||
)
|
||||
)
|
||||
|
||||
@@ -465,7 +463,6 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
|
||||
exclude_none: bool = False,
|
||||
encoder: Optional[Callable[[Any], Any]] = None,
|
||||
models_as_dict: bool = True,
|
||||
use_nested_encoders: bool = False,
|
||||
**dumps_kwargs: Any,
|
||||
) -> str:
|
||||
"""
|
||||
@@ -493,7 +490,6 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
|
||||
exclude_unset=exclude_unset,
|
||||
exclude_defaults=exclude_defaults,
|
||||
exclude_none=exclude_none,
|
||||
encode_as_json=use_nested_encoders,
|
||||
)
|
||||
)
|
||||
if self.__custom_root_type__:
|
||||
@@ -714,7 +710,6 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
|
||||
exclude_unset: bool,
|
||||
exclude_defaults: bool,
|
||||
exclude_none: bool,
|
||||
encode_as_json: bool = False,
|
||||
) -> Any:
|
||||
|
||||
if isinstance(v, BaseModel):
|
||||
@@ -726,7 +721,6 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
|
||||
include=include,
|
||||
exclude=exclude,
|
||||
exclude_none=exclude_none,
|
||||
encode_as_json=encode_as_json,
|
||||
)
|
||||
if ROOT_KEY in v_dict:
|
||||
return v_dict[ROOT_KEY]
|
||||
@@ -776,9 +770,6 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
|
||||
elif isinstance(v, Enum) and getattr(cls.Config, 'use_enum_values', False):
|
||||
return v.value
|
||||
|
||||
elif encode_as_json:
|
||||
return cls.__json_encoder__(v)
|
||||
|
||||
else:
|
||||
return v
|
||||
|
||||
@@ -812,7 +803,6 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
|
||||
exclude_unset: bool = False,
|
||||
exclude_defaults: bool = False,
|
||||
exclude_none: bool = False,
|
||||
encode_as_json: bool = False,
|
||||
) -> 'TupleGenerator':
|
||||
|
||||
# Merge field set excludes with explicit exclude parameter with explicit overriding field set options.
|
||||
@@ -858,7 +848,6 @@ class BaseModel(Representation, metaclass=ModelMetaclass):
|
||||
exclude_unset=exclude_unset,
|
||||
exclude_defaults=exclude_defaults,
|
||||
exclude_none=exclude_none,
|
||||
encode_as_json=encode_as_json,
|
||||
)
|
||||
yield dict_key, v
|
||||
|
||||
|
||||
@@ -372,81 +372,3 @@ def test_recursive():
|
||||
nested: Optional[BaseModel]
|
||||
|
||||
assert Model(value=None, nested=Model(value=None)).json(exclude_none=True) == '{"nested": {}}'
|
||||
|
||||
|
||||
class WithCustomEncoders(BaseModel):
|
||||
dt: datetime.datetime
|
||||
diff: datetime.timedelta
|
||||
|
||||
class Config:
|
||||
json_encoders = {
|
||||
datetime.datetime: lambda v: v.timestamp(),
|
||||
datetime.timedelta: timedelta_isoformat,
|
||||
}
|
||||
|
||||
|
||||
ides_of_march = datetime.datetime(44, 3, 15, tzinfo=datetime.timezone.utc)
|
||||
|
||||
child = WithCustomEncoders(
|
||||
dt=datetime.datetime(2032, 6, 1, tzinfo=datetime.timezone.utc),
|
||||
diff=datetime.timedelta(hours=100),
|
||||
)
|
||||
|
||||
|
||||
def test_inner_custom_encoding():
|
||||
assert child.json() == r'{"dt": 1969660800.0, "diff": "P4DT4H0M0.000000S"}'
|
||||
|
||||
|
||||
def test_encoding_in_parent_with_variable_encoders():
|
||||
class ParentWithVariableEncoders(BaseModel):
|
||||
dt: datetime.datetime
|
||||
child: WithCustomEncoders
|
||||
|
||||
class Config:
|
||||
json_encoders = {
|
||||
datetime.datetime: lambda v: v.year,
|
||||
datetime.timedelta: lambda v: v.total_seconds(),
|
||||
}
|
||||
|
||||
parent = ParentWithVariableEncoders(child=child, dt=ides_of_march)
|
||||
|
||||
default = r'{"dt": 44, "child": {"dt": 2032, "diff": 360000.0}}'
|
||||
assert parent.json() == default
|
||||
# turning off models_as_dict defaults to top-level
|
||||
assert parent.json(models_as_dict=False, use_nested_encoders=False) == default
|
||||
assert parent.json(models_as_dict=False, use_nested_encoders=True) == default
|
||||
|
||||
custom = (
|
||||
r'{"dt": 44, ' # parent.dt still uses the year to encode
|
||||
# child uses child.json_encoders to encode
|
||||
r'"child": {"dt": 1969660800.0, "diff": "P4DT4H0M0.000000S"}}'
|
||||
)
|
||||
assert parent.json(use_nested_encoders=True) == custom
|
||||
|
||||
|
||||
def test_encoding_in_parent_with_class_encoders():
|
||||
class ParentWithClassEncoders(BaseModel):
|
||||
dt: datetime.datetime
|
||||
child: WithCustomEncoders
|
||||
|
||||
class Config:
|
||||
json_encoders = {
|
||||
datetime.datetime: lambda v: v.timestamp(),
|
||||
WithCustomEncoders: lambda v: {'dt': v.dt.year},
|
||||
}
|
||||
|
||||
parent = ParentWithClassEncoders(child=child, dt=ides_of_march)
|
||||
|
||||
# when models_as_dict=True, the `WithCustomEncoders` encoder is ignored
|
||||
default = r'{"dt": -60772291200.0, "child": {"dt": 1969660800.0, "diff": 360000.0}}'
|
||||
assert parent.json() == default
|
||||
|
||||
custom_child = r'{"dt": -60772291200.0, "child": {"dt": 1969660800.0, "diff": "P4DT4H0M0.000000S"}}'
|
||||
assert parent.json(use_nested_encoders=True) == custom_child
|
||||
|
||||
# when models_as_dict=False, the parent `WithCustomEncoders` is used
|
||||
# regardless of whatever json_encoders are in WithCustomEncoders.Config
|
||||
|
||||
custom_parent = r'{"dt": -60772291200.0, "child": {"dt": 2032}}'
|
||||
assert parent.json(models_as_dict=False, use_nested_encoders=False) == custom_parent
|
||||
assert parent.json(models_as_dict=False, use_nested_encoders=True) == custom_parent
|
||||
|
||||
Reference in New Issue
Block a user