This release centers on the incorporation of v2 primitives. In the earlier version, Pydantic v1, support was achieved through a series of workarounds involving the manipulation of passed (or annotated) schemas. These schemas were wrapped into an intermediary RootModel to support both Pydantic models and most of the arbitrary annotations.
With v2, pydantic now ships a new primitive -- `TypeAdapter` -- which is well designed for this particular machinery.
Compatibility layer
To support both Pydantic v1 and v2, which might be useful during migration step, I added an indirection level during the import step.
`0.3.0` contains implementations for both versions, with changes in v1 only required to make this compatibility layer to operate, with all behaviour remaining as in `0.2.13`.
Lazy schema evaluation
In `0.2.*` versions, exact schema resolution had been done in three stages:
1. First, the field tried to resolve the passed schema during field descriptor creation.
2. If it's failed, the next attempt had been performed during Django model class preparation, particularly in `contribute_to_class` method.
3. If even step 2 had failed (because of forward references might be still unresolvable at this stage), then the schema evaluation had to be postponed until the first attempt to access the field on model instance (either instance creation, field assignment or so).
In this update, I decided that evaluation logic should be as simple as possible, thus keeping only stage 3, and removing all the dirty logic that supported the machinery around 1 and 2 stages.
To mitigate possible schema evaluation errors, which may appear only in runtime, the field now performs a few checks that are being performed by Django during app development lifecycle:
- `manage.py check`
- `manage.py runserver`
- `manage.py makemigrations`
- `manage.py migrate`
- and so on...
This check is relied on the same mechanics that you might see in plain `JSONField`, complaining on passing mutable structures itself, instead of callables (Django's `field.E010` warning).
Additional integrity checks
Along with the schema evaluation check, the field now performes a few others, to make sure of its integrity:
- `pydantic.E001` (a check from the section above). The schema cannot be resolved. It is most likely a programmatic error -- forward references cannot be resolved in the Django model's execution context.
- `pydantic.E002`. The field's `default=` value cannot be serialized by the specified schema. This may lead to runtime errors during model `.save()` or `.objects.create(...)` methods.
- `pydantic.E003`. If the field contains `include=` or `exclude=` export arguments, there could be a situation that value, written in the database, could not be restored back to python from its serialized form. This check tries to pass the specified default value (or the one that could be inferred directly from the schema, if `default=` is missing), through the whole transformation cycle, yielding a warning if the value could not be transformed back to python.
Additionally, `JSONField`'s `field.E010` warning is suppressed, as it is meaningless due to the nature of field transformations -- we're always getting a new value, not reusing the one passed to `default=` argument.
What's Changed
* Pydantic 2 support by surenkov in https://github.com/surenkov/django-pydantic-field/pull/34
* Django serialization support by amyasnikov in https://github.com/surenkov/django-pydantic-field/pull/41
New Contributors
* amyasnikov made their first contribution in https://github.com/surenkov/django-pydantic-field/pull/41
**Full Changelog**: https://github.com/surenkov/django-pydantic-field/compare/v0.2.14...v0.3.0