Skip to main content

Reusable Django app for dynamic form templates and submissions

Project description

django-kpforms

A reusable Django application for dynamic form templates and submissions, powered by Lit-based web components.

  • Define form templates with sections, groups, and typed fields (numeric, string, text, radio, checkbox, datetime, calculated, ranged-radio)
  • Built-in tolerance checking for numeric and string fields
  • Interactive web component (<dynamic-form>) for end-user submission
  • Visual form-builder web component (<dynamic-form-builder>) for creating and editing templates
  • Printable-form component for generating PDFs via html2pdf.js
  • Full version history for form templates

Table of Contents

  1. Requirements
  2. Installation
  3. Quick Start
  4. Django Models & Helpers
  5. Web Components
  6. CSS Customisation Variables
  7. Contributing / Building from Source

Requirements

  • Python ≥ 3.14
  • Django ≥ 5.0
  • Pydantic ≥ 2.0

Installation

pip install django-kpforms

Or with uv:

uv add django-kpforms

Quick Start

1. Add to INSTALLED_APPS

# settings.py
INSTALLED_APPS = [
    ...
    "kpforms",
]

2. Run migrations

python manage.py migrate

3. Serve static files

django-kpforms ships with a compiled JavaScript bundle (kpforms.js) and KaTeX font files under kpforms/static/.

Make sure Django's static-file serving is configured and collectstatic has been run in production:

python manage.py collectstatic

4. Load the bundle in your template

{% load static %}

<!-- Load the kpforms web-component bundle -->
<script type="module" src="{% static 'kpforms.js' %}"></script>

<!-- Optional: load html2pdf for the printable-form component -->
<script src="{% static 'html2pdf.bundle.min.js' %}"></script>

Django Models & Helpers

Models

Model Description
FormTemplate A versioned form definition. The schema field holds a FormTemplateSchema JSON object.
FormTemplateVersionHistory Immutable snapshot of a FormTemplate at each version.
FormSubmission A single submission against a FormTemplate. Validates and stores tolerance results.

Helper functions (kpforms.helpers)

from kpforms.helpers import (
    create_form_template,
    update_form_template,
    submit_form_data,
    get_form_by_template_id_and_version,
    get_form_template_list,
    get_form_template_list_paginated,
    get_all_results_for_form_template,
)
Function Description
create_form_template(schema, user) Creates a new FormTemplate from a CreateFormTemplateSchema.
update_form_template(schema, user) Saves a new version of an existing template.
submit_form_data(template_id, form_data, user) Validates and saves a FormSubmission.
get_form_by_template_id_and_version(id, version=None) Returns the FormTemplateSchema for a given ID and optional version.
get_form_template_list(only_active=True) Returns a list of {id, name, description} dicts.
get_form_template_list_paginated(page_size, only_active) Returns a Django Paginator.
get_all_results_for_form_template(template_id) Returns all submissions with labelled field data.

Schema classes (kpforms.form_schema)

The core schema models are Pydantic models. The most important ones:

Class Description
FormTemplateSchema Full form definition: title, instruction, sections.
CreateFormTemplateSchema Input payload for creating a template.
UpdateFormTemplateSchema Input payload for updating a template (adds guid).
FormSubmissionSchema Submission payload: data (list of {fieldId, value}), fieldsOutOfTolerance.

Web Components

Include kpforms.js once on the page (see Quick Start above) — all components are self-registering and require no additional setup.

<dynamic-form>

Renders a form for end-user completion and submission.

<dynamic-form id="my-form"></dynamic-form>

<script type="module">
  const formEl = document.getElementById("my-form");

  // Pass the form schema (FormSchema JSON) as a property
  formEl.schema = {
    guid: "...",
    title: "My Form",
    sections: [...],
    generatePdfOption: false,
    generatePdfString: "Generate PDF",
    submitFormString: "Submit",
    submittingString: "Submitting…",
    apiConfig: {
      url: "/api/forms/submit/",
      method: "POST",
      successMessage: "Form submitted!",
      errorMessage: "Submission failed."
    }
  };
</script>

Properties / attributes:

Property Type Description
schema FormSchema (object) The full form schema to render.
lang string BCP-47 language tag for UI strings (e.g. "en", "sv"). Defaults to "en".

<dynamic-form-builder>

An interactive editor that lets users create and edit form templates.

<dynamic-form-builder id="builder"></dynamic-form-builder>

<script type="module">
  const builder = document.getElementById("builder");

  // Optional: load an existing template for editing
  builder.schema = { guid: "...", name: "...", formSchema: { ... } };

  // Listen for save events
  builder.addEventListener("form-save", (e) => {
    const payload = e.detail; // CreateFormTemplateSchema | UpdateFormTemplateSchema
    fetch("/api/forms/templates/", {
      method: payload.guid ? "PUT" : "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(payload),
    });
  });
</script>

Properties / attributes:

Property Type Description
schema UpdateFormTemplateSchema (object) Optional existing template to edit.
lang string BCP-47 language tag.

Events emitted:

Event detail Description
form-save CreateFormTemplateSchema | UpdateFormTemplateSchema Fired when the user clicks Save.

<printable-form>

Renders a read-only printable view of a submitted form that can be exported as a PDF using html2pdf.js.

<printable-form id="print-form"></printable-form>

<script type="module">
  const el = document.getElementById("print-form");
  el.schema   = { /* FormTemplateSchema */ };
  el.submission = { /* FormSubmission data */ };
</script>

Properties:

Property Type Description
schema FormTemplateSchema (object) The form template.
submission FormSubmissionSchema (object) The submission data to display.

CSS Customisation Variables

All web components use CSS custom properties (variables) to control their appearance. Set these on the element itself or any ancestor to theme the components.

The public API variables are prefixed --df-*. Internal variables map them to --form-* and to Shoelace design tokens.

Typography

Variable Default Description
--df-font-size-base 1rem Base font size.
--df-font-size-h1 1.8rem Form title size.
--df-font-size-h2 1.4rem Section heading size.
--df-font-size-label 0.9rem Field label size.
--df-font-size-description 0.85rem Field description / helper text size.

Colours

Variable Default Description
--df-color-text #333 Primary text colour.
--df-color-input-text #111 Text colour inside input fields.
--df-color-text-secondary #555 Secondary / description text colour.
--df-color-text-label #111 Field label text colour.
--df-color-background #ffffff Component background.
--df-color-background-input-base #ffffff Input field background (resting).
--df-color-background-input-focus #ffffff Input field background on focus.
--df-color-background-section #f9f9f9 Form section background.
--df-color-border #ccc Default border colour.

Accent Colour

Used for buttons, active tabs, focused borders, and Shoelace's primary palette.

Variable Default Description
--df-color-accent #007bff Primary accent / brand colour.
--df-color-accent-lighter #66b3ff Lighter variant (e.g. hover states).
--df-color-accent-darker #0056b3 Darker variant (e.g. active states).
--df-color-accent-text #ffffff Text on accent-coloured elements.
--df-color-success #28a745 Success colour (Shoelace success palette).
--df-color-success-darker #1e7e34 Darker success variant.
--df-color-success-text #ffffff Text on success-coloured elements.
--df-color-warning #fbb34e Warning colour.
--df-color-warning-darker #fea429 Darker warning variant.
--df-color-warning-text #ffffff Text on warning-coloured elements.
--df-color-neutral #6c757d Neutral colour.
--df-color-neutral-darker #5a6268 Darker neutral variant.
--df-color-neutral-text #ffffff Text on neutral-coloured elements.
--df-color-error #dc3545 Error / danger colour.
--df-color-error-lighter #fa5969 Lighter error variant.
--df-color-error-text #721c24 Text on error-coloured elements.

Status / Tolerance Colours

These control how fields are highlighted when their values are within or outside the defined tolerance range.

Variable Default Description
--df-color-required-star #f98989 Colour of the asterisk on required fields.
--df-color-within-tolerance-border #8fff8f Border colour when field value is within tolerance.
--df-color-within-tolerance-background #b9fb9f Background when field value is within tolerance.
--df-color-within-tolerance-input-text #214521 Text colour in input when within tolerance.
--df-color-within-tolerance-text #3c763d Label/message text when within tolerance.
--df-color-out-of-tolerance-border #fdf8b2 Border colour when field value is out of tolerance.
--df-color-out-of-tolerance-text #d9534f Text/label colour when out of tolerance.
--df-color-has-error-border (inherits error colour) Border colour when field has a validation error.
--df-color-has-error-background #d58d8b Background when field has a validation error.

Layout

Variable Default Description
--df-border-radius 4px Corner radius for inputs, sections, and the component itself.
--df-spacing-medium 1rem Medium spacing unit used for padding/gaps.
--df-spacing-large 1.5rem Large spacing unit used for section padding.
--df-button-padding 0.3rem 1rem Padding applied to Shoelace <sl-button> elements.

Example: Dark Theme

dynamic-form {
  --df-color-background:            #1e1e2e;
  --df-color-background-section:    #2a2a3e;
  --df-color-background-input-base: #2d2d42;
  --df-color-text:                  #cdd6f4;
  --df-color-text-label:            #cdd6f4;
  --df-color-input-text:            #cdd6f4;
  --df-color-border:                #45475a;
  --df-color-accent:                #89b4fa;
  --df-color-accent-darker:         #74a0e8;
  --df-color-accent-text:           #1e1e2e;
}

Contributing / Building from Source

Prerequisites

  • Python ≥ 3.14 (with uv)
  • Node.js ≥ 20 with npm

Build

Use the included build.sh to produce a distributable wheel and sdist:

# Build both sdist and wheel (default)
./build.sh

# Build wheel only
./build.sh --wheel

# Build sdist only
./build.sh --sdist

The script will:

  1. Run npm run build inside kpforms/kpforms/ to compile the TypeScript web components and copy the output into kpforms/static/.
  2. Run python manage.py makemigrations kpforms to ensure migrations are up-to-date.
  3. Run uv build to produce the final packages in dist/.

Running Tests

uv run pytest

Licence

MIT — see LICENSE for details.

Project details


Download files

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

Source Distributions

No source distribution files available for this release.See tutorial on generating distribution archives.

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_kpforms-0.1.0-py3-none-any.whl (2.2 MB view details)

Uploaded Python 3

File details

Details for the file django_kpforms-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: django_kpforms-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 2.2 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.5

File hashes

Hashes for django_kpforms-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b207e536f1cedf6b01b6ba6816a758339c2b4b889d83b97c813435f596dfd0b7
MD5 9db378b2e8bd2bf3b7d36aa0631e787a
BLAKE2b-256 a3fedaceb8438891ad184ee68f8b4dd6c8ebf1c2c6c892d7a73ae193d27c723c

See more details on using hashes here.

Supported by

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