Skip to main content

A Django-Ninja backend to specify FormKit schemas

Project description

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

Project details


Release history Release notifications | RSS feed

This version

2.2

Download files

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

Source Distribution

formkit_ninja-2.2.tar.gz (1.2 MB view details)

Uploaded Source

Built Distribution

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

formkit_ninja-2.2-py3-none-any.whl (641.5 kB view details)

Uploaded Python 3

File details

Details for the file formkit_ninja-2.2.tar.gz.

File metadata

  • Download URL: formkit_ninja-2.2.tar.gz
  • Upload date:
  • Size: 1.2 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Bluefin","version":"43","id":"Deinonychus","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for formkit_ninja-2.2.tar.gz
Algorithm Hash digest
SHA256 fe02a663e2bbd92f7a3f2c013ba9277726425191ff29d15dddeb282dfa3f2a64
MD5 32680525ce91aa133ebebef60abac7c9
BLAKE2b-256 a71ecc0c4474430f57517028a06af1a9ed0709abf27f4a086b48a4150504f932

See more details on using hashes here.

File details

Details for the file formkit_ninja-2.2-py3-none-any.whl.

File metadata

  • Download URL: formkit_ninja-2.2-py3-none-any.whl
  • Upload date:
  • Size: 641.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: uv/0.10.8 {"installer":{"name":"uv","version":"0.10.8","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Bluefin","version":"43","id":"Deinonychus","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

File hashes

Hashes for formkit_ninja-2.2-py3-none-any.whl
Algorithm Hash digest
SHA256 13fba0c06feddefe07f9309cf94c66bd8b79c2383f06ba7db88bff63911cdc89
MD5 ddb5cfdff3b326f8a7fddc35b3193c7e
BLAKE2b-256 668aab1abf158a2aa911f7e071382e8d9952db152cd1958e690061595c971417

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