* Add (failing) test for Subclass JSON encoding * Allow subclasses of known types to be encoded with superclass encoder * Add change file * Add documentation, fix custom json_encoders and add unit test Blacken doc Fix test that worked on my machine datetime.timestamp() is flakey? Single quotes only * Reduce lookups - Remove last element in `__mro__` as it will always be `object` - Use .get for compactness * Regarding the loop * Move Path and Enum into ENCODERS_BY_TYPE Sort ENCODERS_BY_TYPE * improve JSON docs Co-authored-by: Samuel Colvin <s@muelcolvin.com>
6.7 KiB
As well as accessing model attributes directly via their names (e.g. model.foobar), models can be converted
and exported in a number of ways:
model.dict(...)
This is the primary way of converting a model to a dictionary. Sub-models will be recursively converted to dictionaries.
Arguments:
include: fields to include in the returned dictionary; see belowexclude: fields to exclude from the returned dictionary; see belowby_alias: whether field aliases should be used as keys in the returned dictionary; defaultFalseexclude_unset: whether fields which were not explicitly set when creating the model should be excluded from the returned dictionary; defaultFalse. Prior to v1.0,exclude_unsetwas known asskip_defaults; use ofskip_defaultsis now deprecatedexclude_defaults: whether fields which are equal to their default values (whether set or otherwise) should be excluded from the returned dictionary; defaultFalseexclude_none: whether fields which are equal toNoneshould be excluded from the returned dictionary; defaultFalse
Example:
{!.tmp_examples/exporting_models_dict.py!}
(This script is complete, it should run "as is")
dict(model) and iteration
pydantic models can also be converted to dictionaries using dict(model), and you can also
iterate over a model's field using for field_name, value in model:. With this approach the raw field values are
returned, so sub-models will not be converted to dictionaries.
Example:
{!.tmp_examples/exporting_models_iterate.py!}
(This script is complete, it should run "as is")
model.copy(...)
copy() allows models to be duplicated, which is particularly useful for immutable models.
Arguments:
include: fields to include in the returned dictionary; see belowexclude: fields to exclude from the returned dictionary; see belowupdate: a dictionary of values to change when creating the copied modeldeep: whether to make a deep copy of the new model; defaultFalse
Example:
{!.tmp_examples/exporting_models_copy.py!}
(This script is complete, it should run "as is")
model.json(...)
The .json() method will serialise a model to JSON. Typically, .json() in turn calls .dict() and
serialises its result. (For models with a custom root type, after calling .dict(),
only the value for the __root__ key is serialised)
Arguments:
include: fields to include in the returned dictionary; see belowexclude: fields to exclude from the returned dictionary; see belowby_alias: whether field aliases should be used as keys in the returned dictionary; defaultFalseexclude_unset: whether fields which were not set when creating the model and have their default values should be excluded from the returned dictionary; defaultFalse. Prior to v1.0,exclude_unsetwas known asskip_defaults; use ofskip_defaultsis now deprecatedexclude_defaults: whether fields which are equal to their default values (whether set or otherwise) should be excluded from the returned dictionary; defaultFalseexclude_none: whether fields which are equal toNoneshould be excluded from the returned dictionary; defaultFalseencoder: a custom encoder function passed to thedefaultargument ofjson.dumps(); defaults to a custom encoder designed to take care of all common types**dumps_kwargs: any other keyword arguments are passed tojson.dumps(), e.g.indent.
pydantic can serialise many commonly used types to JSON (e.g. datetime, date or UUID) which would normally
fail with a simple json.dumps(foobar).
{!.tmp_examples/exporting_models_json.py!}
(This script is complete, it should run "as is")
json_encoders
Serialisation can be customised on a model using the json_encoders config property; the keys should be types, and
the values should be functions which serialise that type (see the example below):
{!.tmp_examples/exporting_models_json_encoders.py!}
(This script is complete, it should run "as is")
By default, timedelta is encoded as a simple float of total seconds. The timedelta_isoformat is provided
as an optional alternative which implements ISO 8601 time diff encoding.
Serialising subclasses
!!! note New in version v1.5.
Subclasses of common types were not automatically serialised to JSON before **v1.5**.
Subclasses of common types are automatically encoded like their super-classes:
{!.tmp_examples/exporting_models_json_subclass.py!}
(This script is complete, it should run "as is")
Custom JSON (de)serialisation
To improve the performance of encoding and decoding JSON, alternative JSON implementations
(e.g. ujson) can be used via the
json_loads and json_dumps properties of Config.
{!.tmp_examples/exporting_models_ujson.py!}
(This script is complete, it should run "as is")
ujson generally cannot be used to dump JSON since it doesn't support encoding of objects like datetimes and does
not accept a default fallback function argument. To do this, you may use another library like
orjson.
{!.tmp_examples/exporting_models_orjson.py!}
(This script is complete, it should run "as is")
Note that orjson takes care of datetime encoding natively, making it faster than json.dumps but
meaning you cannot always customise the encoding using Config.json_encoders.
pickle.dumps(model)
Using the same plumbing as copy(), pydantic models support efficient pickling and unpickling.
{!.tmp_examples/exporting_models_pickle.py!}
(This script is complete, it should run "as is")
Advanced include and exclude
The dict, json, and copy methods support include and exclude arguments which can either be
sets or dictionaries. This allows nested selection of which fields to export:
{!.tmp_examples/exporting_models_exclude1.py!}
The ellipsis (...) indicates that we want to exclude or include an entire key, just as if we included it in a set.
Of course, the same can be done at any depth level.
Special care must be taken when including or excluding fields from a list or tuple of submodels or dictionaries. In this scenario,
dict and related methods expect integer keys for element-wise inclusion or exclusion. To exclude a field from every
member of a list or tuple, the dictionary key '__all__' can be used as follows:
{!.tmp_examples/exporting_models_exclude2.py!}
The same holds for the json and copy methods.