Skip to main content

Django JSONField with Pydantic models as a Schema

Project description

PyPI Version

Django + Pydantic = 🖤

Django JSONField with Pydantic models as a Schema

Usage

Install the package with pip install django-pydantic-field.

import pydantic

from django.db import models
from django_pydantic_field import PydanticSchemaField


class Foo(pydantic.BaseModel):
    count: int
    size: float = 1.0


class Bar(pydantic.BaseModel):
    slug: str = "foo_bar"


class MyModel(models.Model):
    foo_field = PydanticSchemaField(schema=Foo)
    bar_list = PydanticSchemaField(schema=list[Bar])

...
    
model = MyModel(foo_field={"count": "5"}, bar_list=[{}])
model.save()

assert model.foo_field == Foo(count=5, size=1.0)
assert model.bar_list == [Bar(slug="foo_bar")]

Django REST Framework support

from rest_framework import serializers
from django_pydantic_field.rest_framework import PydanticSchemaField


class MyModelSerializer(serializers.ModelSerializer):
    foo_field = PydanticSchemaField(schema=Foo)

    class Meta:
        model = MyModel
        fields = '__all__'

Global approach with typed parser and renderer classes

from rest_framework import views
from rest_framework.decorators import api_view, parser_classes, renderer_classes
from django_pydantic_field.rest_framework import PydanticSchemaRenderer, PydanticSchemaParser


@api_view(["POST"])
@parser_classes([PydanticSchemaParser[Foo]]):
@renderer_classes([PydanticSchemaRenderer[list[Foo]]])
def foo_view(request):
    assert isinstance(request.data, Foo)

    count = request.data.count + 1
    return Response([Foo(count=count)])


class FooClassBasedView(views.APIView):
    parser_classes = [PydanticSchemaParser[Foo]]
    renderer_classes = [PydanticSchemaRenderer[list[Foo]]]

    def get(self, request, *args, **kwargs):
        assert isinstance(request.data, Foo)
        return Response([request.data])

    def put(self, request, *args, **kwargs):
        assert isinstance(request.data, Foo)

        count = request.data.count + 1
        return Response([request.data])

Caveats

  • Built-in generic annotations introduced in Python 3.9 are expecting to fail during manage.py makemigrations step: due to how Django treats field serialization/reconstruction while writing migrations, it is not possible to create a custom serializer to distinguish between types.GenericAlias and a type instance (any class) without pushing a patch directly in Django.

    A workaround is to use generic collections from typing module, even though they're marked as deprecated and will be eventually removed in the future versions of Python.

    Note, that this restriction applies only for PydanticSchemaField. DRF integrations sould work fine though.

Acknowledgement

  • Churkin Oleg for his Gist as a source of inspiration;
  • Boutique Air Flight Operations platform as a test ground;

Project details


Release history Release notifications | RSS feed

This version

0.0.5

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django-pydantic-field-0.0.5.tar.gz (7.5 kB view hashes)

Uploaded Source

Built Distribution

django_pydantic_field-0.0.5-py3-none-any.whl (8.3 kB view hashes)

Uploaded Python 3

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page