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
- Requirements
- Installation
- Quick Start
- Django Models & Helpers
- Web Components
- CSS Customisation Variables
- 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:
- Run
npm run buildinsidekpforms/kpforms/to compile the TypeScript web components and copy the output intokpforms/static/. - Run
python manage.py makemigrations kpformsto ensure migrations are up-to-date. - Run
uv buildto produce the final packages indist/.
Running Tests
uv run pytest
Licence
MIT — see LICENSE for details.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b207e536f1cedf6b01b6ba6816a758339c2b4b889d83b97c813435f596dfd0b7
|
|
| MD5 |
9db378b2e8bd2bf3b7d36aa0631e787a
|
|
| BLAKE2b-256 |
a3fedaceb8438891ad184ee68f8b4dd6c8ebf1c2c6c892d7a73ae193d27c723c
|