Skip to content

Dynamic schemas and context

schema may be a dictionary or a callable. A callable with one parameter receives the current form context; a zero-argument callable is also accepted.

def configuration_schema(context):
    properties = {
        "title": {"type": "string"},
    }
    if context.user.has_perm("catalog.set_internal_code"):
        properties["internal_code"] = {"type": "string"}
    if context.obj and context.obj.pk:
        properties["slug"] = {"type": "string", "readOnly": True}
    return {
        "type": "object",
        "properties": properties,
        "required": ["title"],
    }

Pass a dictionary, namespace, or application object as json_form_context:

form = ProductForm(
    request.POST or None,
    instance=product,
    json_form_context={
        "user": request.user,
        "request": request,
        "obj": product,
        "tenant": request.tenant,
    },
)

Dictionary context is converted into an attribute-accessible namespace and receives form. When no context is provided, the mixin supplies:

  • obj: the ModelForm instance when available;
  • form: the current form;
  • a non-privileged fallback user.

This fallback prevents schema callables from accidentally assuming an anonymous operation has permissions.

Preserve hidden values

Dynamic schemas often omit fields the current user cannot see. The ModelForm mixin keeps the initial JSON as the binding's source so omitted or unknown keys survive a valid submission. Marking a node readonly likewise returns its initial value instead of trusting posted browser data.

Do not use a dynamic schema as the only authorization check for unrelated model operations. Normal Django view/admin permissions still apply.