Skip to content

Quick start

Assume the model stores arbitrary product configuration:

from django.db import models


class Product(models.Model):
    name = models.CharField(max_length=200)
    configuration = models.JSONField(default=dict, blank=True)

Define a schema on the form, not on the model field:

from django_native_jsonform import JSONSchemaFormField, JSONSchemaModelForm

from .models import Product


PRODUCT_SCHEMA = {
    "type": "object",
    "title": "Configuration",
    "properties": {
        "description": {
            "type": "string",
            "title": "Description",
            "widget": "textarea",
        },
        "price": {
            "type": "number",
            "minimum": 0,
        },
        "labels": {
            "type": "array",
            "items": {"type": "string"},
            "maxItems": 10,
        },
    },
    "required": ["price"],
}


class ProductForm(JSONSchemaModelForm):
    configuration = JSONSchemaFormField(
        schema=PRODUCT_SCHEMA,
        required=False,
    )

    class Meta:
        model = Product
        fields = "__all__"

Use it like any ModelForm:

def edit_product(request, pk):
    product = get_object_or_404(Product, pk=pk)
    form = ProductForm(
        request.POST or None,
        request.FILES or None,
        instance=product,
        json_form_context={
            "request": request,
            "user": request.user,
            "obj": product,
        },
    )
    if form.is_valid():
        form.save()
        return redirect("product-detail", pk=product.pk)
    return render(request, "products/edit.html", {"form": form})

The template does not require a special renderer:

<form method="post" enctype="multipart/form-data">
  {% csrf_token %}
  {{ form.media }}
  {{ form.as_div }}
  <button type="submit">Save</button>
</form>

JSONSchemaModelForm already includes the context/preservation mixin. When a project must inherit from another custom ModelForm, use JSONSchemaModelFormMixin before that class instead.

class ProductForm(JSONSchemaModelFormMixin, ExistingProductForm):
    configuration = JSONSchemaFormField(schema=PRODUCT_SCHEMA)

The mixin seeds the generated binding with the original JSON. Without it, unknown values or schema branches hidden by permissions cannot be preserved reliably.