Skip to main content

Formkit-Ninja

A Django-Ninja framework for FormKit schemas and form submissions

Why

FormKit out of the box has awesome schema support - this lets us integrate FormKit instances as Django models

  • Upload / edit / download basic FormKit schemas
  • Translated "option" values from the Django admin
  • Reorder "options" and schema nodes
  • List and Fetch schemas for different form types

Use

To use, pip install formkit-ninja and add the following to settings INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    "formkit_ninja",
    "ninja",
    ...
]

Quick Start for New Users

⭐ NEW - Create complete data collection apps with minimal coding!

# 1. Create a FormKit schema
./manage.py create_schema --label "Contact Form"

# 2. Bootstrap a complete Django app
./manage.py bootstrap_app --schema-label "Contact Form" --app-name contacts

# 3. Add to INSTALLED_APPS and migrate
# (Edit settings.py to add 'contacts')
./manage.py makemigrations && ./manage.py migrate

# 4. Start collecting data!
./manage.py runserver

See the Quick Start Guide for a complete walkthrough.

Code Generation

⭐ NEW in v0.8.1 - Database-driven code generation! Configure type mappings and field overrides through Django admin without writing Python code.

formkit-ninja can automatically generate Django models, Pydantic schemas, admin classes, and API endpoints from your FormKit schemas.

Database-Driven Configuration

Configure code generation rules through the Django admin:

# Django Admin → Code generation configs
formkit_type = "text"
node_name = "district"
django_type = "ForeignKey"
django_args = {"to": "pnds_data.zDistrict", "on_delete": "models.CASCADE"}

Generates:

# models.py
district = models.ForeignKey("pnds_data.zDistrict", on_delete=models.CASCADE)

Quick Start

Generate code from all schemas in your database:

./manage.py generate_code --app-name myapp --output-dir ./myapp/generated

Generate code for a specific schema:

./manage.py generate_code --app-name myapp --output-dir ./myapp/generated --schema-label "My Form"

Generated Files

The code generator creates the following files:

  • models.py - Django models for groups and repeaters
  • schemas.py - Django Ninja output schemas
  • schemas_in.py - Django Ninja input schemas (Pydantic BaseModel)
  • admin.py - Django admin classes
  • api.py - Django Ninja API endpoints

Extensibility

formkit-ninja provides multiple extension points for customizing code generation:

  • Database-Driven Config: Configure through Django admin (no code needed!) ⭐ NEW
  • Custom Type Converters: Add support for custom FormKit node types
  • Custom NodePath: Extend NodePath with project-specific logic
  • Plugin System: Bundle multiple extensions together
  • Custom Templates: Override Jinja2 templates for generated code

See the Database-Driven Code Generation guide for the new database configuration feature, or the Code Generation Guide for detailed documentation and examples.

API

Formkit-Ninja provides a REST API for managing FormKit schema nodes. The API requires authentication and specific permissions.

Authentication

All API endpoints require:

  • Authentication: User must be logged in (session-based authentication)
  • Permission: User must have the formkit_ninja.change_formkitschemanode permission

Unauthenticated requests receive 401 Unauthorized. Authenticated users without the required permission receive 403 Forbidden.

Endpoints

Create or Update Node

POST /api/formkit/create_or_update_node

Creates a new node or updates an existing one.

Request Body:

  • uuid (optional): UUID of node to update. If omitted, a new node is created.
  • parent_id (optional): UUID of parent node (must be a group or repeater)
  • $formkit: FormKit node type (e.g., "text", "group", "repeater")
  • Other FormKit node properties (label, name, etc.)

Response:

  • 200 OK: Success, returns NodeReturnType with node data
  • 400 Bad Request: Invalid input (e.g., invalid parent, deleted node)
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Node with provided UUID does not exist (for updates)
  • 500 Internal Server Error: Server error

Update Behavior:

  • When uuid is provided, the node with that UUID is updated
  • If the node doesn't exist, returns 404 Not Found
  • If the node is inactive (deleted), returns 400 Bad Request
  • Parent-child relationships are automatically created/updated when parent_id is provided

Delete Node

DELETE /api/formkit/delete/{node_id}

Soft deletes a node (sets is_active=False).

Response:

  • 200 OK: Success, returns NodeInactiveType
  • 403 Forbidden: Insufficient permissions
  • 404 Not Found: Node does not exist

Response Formats

All successful responses return consistent data structures:

  • NodeReturnType: For active nodes

    • key: UUID of the node
    • node: FormKit node data
    • last_updated: Timestamp of last change
    • protected: Whether the node is protected from deletion
  • NodeInactiveType: For deleted nodes

    • key: UUID of the node
    • is_active: false
    • last_updated: Timestamp of last change
    • protected: Whether the node is protected
  • FormKitErrors: For error responses

    • errors: List of error messages
    • field_errors: Dictionary of field-specific errors

Validation

The API validates:

  • Parent existence: If parent_id is provided, the parent node must exist and be a group or repeater
  • Node existence: If uuid is provided for updates, the node must exist and be active
  • FormKit type: The $formkit field must be a valid FormKit node type

Test

Pull the repo:

gh repo clone catalpainternational/formkit-ninja
cd formkit-ninja
uv sync

Database Setup

Tests and submission queryset annotations (e.g. with_unresolved_flags(), with_import_failure()) require PostgreSQL (pgtrigger, and JSONBAgg/JSONObject for annotations). Start a PostgreSQL container before running tests:

# Using Podman (recommended)
podman run --replace -d --name formkit-postgres -p 5434:5432 -e POSTGRES_HOST_AUTH_METHOD=trust docker.io/library/postgres:14-alpine

# OR using Docker
docker run -d --name formkit-postgres -p 5434:5432 -e POSTGRES_HOST_AUTH_METHOD=trust postgres:14-alpine

Then run tests:

uv run pytest

Playwright

Some tests require playwright. Install it with:

uv run playwright install

Note: For full development setup with real data, see DEVELOPMENT.md.

Lint

Format and lint code using ruff:

# Check formatting
uv run ruff format --check .

# Check linting
uv run ruff check .

For Contributors

Prerequisites

  • Python 3.10-3.14
  • uv for package management
  • Podman or Docker for PostgreSQL database
  • Playwright (for browser-based tests)

Development Workflow

  1. Set up the project:

    uv sync
    uv run playwright install
    # Start PostgreSQL (see Database Setup above)
    
  2. Run tests:

    uv run pytest
    
  3. Check code quality:

    uv run ruff format --check .
    uv run ruff check .
    uv run mypy formkit_ninja
    
  4. Test Driven Development (TDD):

    • Write tests before implementing features
    • Ensure new code is covered by tests
    • Use pytest as the testing framework
  5. Code Style:

    • Use ruff for formatting and linting
    • Follow Python type hints for all function arguments and return values
    • Adhere to SOLID principles
  6. Commit Messages:

Updating 'Protected' Nodes

If a node's been protected you cannot change or delete it. To do so, you'll need to temporarily disable the trigger which is on it.

./manage.py pytrigger disable protect_node_deletes_and_updates Make changes ./manage.py pgtrigger enable protect_node_deletes_and_updates

See the documentation for more details: https://django-pgtrigger.readthedocs.io/en/2.3.0/commands.html?highlight=disable

Metadata

Release files for formkit-ninja 4.0.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for formkit-ninja 4.0.0
File Size Uploaded
formkit_ninja-4.0.0.tar.gz 881.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for formkit-ninja 4.0.0
File Interpreter ABI Platform
formkit_ninja-4.0.0-py3-none-any.whl Python 3 none any Details

Total release size: 1.3 MB

Release files / formkit_ninja-4.0.0.tar.gz

Download URL formkit_ninja-4.0.0.tar.gz
Size 881.2 kB
Tags Source
SHA-256 checksum
How to use checksums
700afae44e3401b779a38463d8dd5d6eb54f7c8fecd186565b9d8f86be361ebe
BLAKE2b-256 checksum
How to use checksums
6f614d28409601a81b7dcc5fa860c672a14902ad06899d41f84a0ce2806b0940
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.

Transparency log

Release files / formkit_ninja-4.0.0-py3-none-any.whl

Download URL formkit_ninja-4.0.0-py3-none-any.whl
Size 438.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
dc7c3d5dbca6ae6b9985d27b7fd8db7a9ea2aa3b2518f73c7941b9e74186e8e9
BLAKE2b-256 checksum
How to use checksums
181d490d0b71c9bbb85fb4f1a15bb0fb2715fd2b9b464893ea30188e79a5e96b
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.

Transparency log

Release history Release notifications | RSS feed

6.1.2

2 release files

6.1.1

2 release files

6.1.0

2 release files

6.0.0

2 release files

5.0.0

2 release files

4.4.0

2 release files

4.3.0

2 release files

4.2.0

2 release files

4.1.0

2 release files

4.0.2

2 release files

4.0.1

2 release files

This release

4.0.0 This release

2 release files

3.4.1

2 release files

3.4.0

2 release files

3.3.0

2 release files

3.2.0

2 release files

3.1.0

2 release files

3.0.0

2 release files

2.6.0

2 release files

2.5.4

2 release files

2.5.3

2 release files

2.5.2

2 release files

2.5.1

2 release files

2.5

2 release files

2.4

2 release files

2.3

2 release files

2.2

2 release files

2.1

2 release files

0.8.1

2 release files

0.8.0

2 release files

0.7.6

2 release files

0.7.5

2 release files

0.7.4

2 release files

0.7.3

2 release files

0.7.2

2 release files

0.7.1

2 release files

0.7.0

2 release files

0.6.5

2 release files

0.6.4

2 release files

0.6.3

2 release files

0.6.2

2 release files

0.6.1

2 release files

0.6.0

2 release files

0.5.2

2 release files

0.5.1

2 release files

0.5.0

2 release files

0.3.5

2 release files

0.3.4

2 release files

0.3.3

2 release files

0.3.2

2 release files

0.3.1

2 release files

0.3.0

2 release files

0.1.6

2 release files

0.1.5

2 release files

0.1.4

2 release files

0.1.3

2 release files

0.1.2

2 release files

0.1.1

2 release files

0.1.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page