Skip to content

Latest commit

 

History

History
427 lines (352 loc) · 21.3 KB

File metadata and controls

427 lines (352 loc) · 21.3 KB

Django Forms Workflows

Enterprise-grade, database-driven form builder with multi-stage approval workflows, external data integration, and cross-instance sync

License: LGPL v3 Python Version Django Version Version

Overview

Django Forms Workflows bridges the gap between simple form libraries (like Crispy Forms) and expensive SaaS solutions (like JotForm, Formstack). It provides:

  • 📝 Database-Driven Forms — Define forms in the database, not code. 25+ field types including calculated/formula fields and spreadsheet uploads.
  • 🔄 Multi-Stage Approval Workflows — Sequential, parallel, or hybrid approval flows with configurable stages and conditional trigger logic.
  • ↩️ Send Back for Correction — Approvers can return a submission to any prior stage without terminating the workflow.
  • 🎯 Dynamic Assignees — Resolve individual approvers at submit time from form field values (email, username, full name, or LDAP lookup).
  • 🔀 Sub-Workflows — Spawn child workflows from a parent submission (e.g. one form creates N payment approvals).
  • 🔌 External Data Integration — Prefill fields from LDAP, databases, REST APIs, or the Django user model.
  • Post-Submission Actions — Trigger emails, database writes, LDAP updates, or custom Python handlers on submit/approve/reject.
  • 🔄 Cross-Instance Sync — Push/pull form definitions between environments directly from the Django Admin.
  • 🔒 Enterprise Security — LDAP/AD & SSO authentication, RBAC with four permission tiers, complete audit trails.
  • 🌐 REST API — Opt-in Bearer-token API: list forms, fetch field schema, submit (or save draft), poll status. OpenAPI 3.0 schema + Swagger UI included.
  • 🖼️ Embeddable Forms — Embed forms on any website via a <script> tag or <iframe>. Auto-resize, theme/accent color support, postMessage callbacks. WordPress plugin included.
  • 💳 Pluggable Payments — Collect payments during form submission with a pluggable provider system. Stripe ships built-in; add custom providers via register_provider().
  • 📋 Shared Option Lists — Define reusable choice lists once, reference from any form field. Update the list and every field reflects the change.
  • 🔗 Dependent Workflows — Workflows that start only after all other workflows on the form complete, enabling convergence gates after parallel tracks.
  • 📁 Managed File Uploads — File uploads with approval, rejection, and version tracking per submission.
  • 🧮 Formula Fields — Calculated fields that compute values live from other field values using a template formula.
  • 🏠 Self-Hosted — No SaaS fees, full data control.

Key Features

🎯 No-Code Form Creation

Business users create and modify forms through Django Admin:

  • 25+ field types: text, email, phone, select, radio, checkbox, checkboxes, multiselect, date, time, datetime, decimal, currency, number, URL, file, multi-file, textarea, hidden, section headers, calculated/formula, spreadsheet upload (CSV/Excel), country picker, US state picker, signature (draw or type)
  • Field ordering with explicit order integer
  • Column-width layout per field: full, half, one-third, one-quarter
  • Validation rules (required, regex, min/max length, min/max value)
  • Conditional field visibility (show_if_field / show_if_value)
  • Custom help text, placeholders, and CSS classes
  • Read-only and pre-filled fields
  • Draft saving with auto-save support

🔄 Multi-Stage Approval Workflows

Flexible approval engine built on WorkflowStage records:

  • Each stage has its own approval groups and logic (any / all / sequence)
  • Stages execute in order; next stage unlocks when the current one completes
  • Multiple WorkflowDefinition records can run as parallel approval tracks on the same form
  • Conditional stages — each stage can carry trigger_conditions JSON; stages whose conditions don't match the submission data are automatically skipped
  • Workflow-level trigger conditions — entire parallel approval tracks are skipped when their workflow trigger_conditions don't match (e.g. only trigger a Finance track when amount > 10000)
  • Dynamic individual assignees — set assignee_form_field + assignee_lookup_type (email / username / full_name / ldap) on a stage to resolve the approver from a form field value at runtime; falls back to group tasks when the value cannot be resolved
  • Send Back for Correction — approvers can return a submission to any prior stage that has allow_send_back enabled without terminating the workflow; full audit entry recorded
  • Stage-specific form fields (e.g. approver notes, signature date) appear only during that stage
  • Configurable approval deadline (approval_deadline_days) sets due_date on created tasks
  • Reminder emails (send_reminder_after_days) and optional auto-approval after expiry (auto_approve_after_days)
  • Immediate or batched notifications (immediate / daily / weekly / monthly / form_field_date)
  • Optional per-stage reassignment, editable submission data during approval, custom approve button labels, hidden approval history, and bulk export / bulk PDF export controls
  • Rejection handling with per-stage or global rejection semantics
  • Complete audit trail on every approval, rejection, send-back, and status change
  • First-class outbound webhooks per workflow with signed async delivery, retry/backoff, and delivery logs

See the Workflow Guide, Visual Workflow Builder, Dynamic Assignees, Send Back for Correction, Notifications, and Workflow Webhooks.

🔀 Sub-Workflows

Spawn child workflow instances from a parent submission:

  • SubWorkflowDefinition links a parent workflow to a child form definition
  • count_field controls how many sub-workflows to create (driven by a form field value)
  • section_label and label_template control how child instances are presented in the UI
  • data_prefix slices the parent's form data to populate each child
  • Triggered on_submission or on_approval
  • detached mode lets child instances complete independently of the parent
  • reject_parent=True lets a rejected child immediately reject the parent and cancel sibling child instances
  • Parent submission status reflects aggregate child completion when not detached
  • Sub-workflows support the same send-back mechanism via handle_sub_workflow_send_back

See Sub-Workflows Guide for a full walkthrough.

🖼️ Embeddable Forms

Embed DFW forms on any external website:

  • Single <script> tag creates a responsive iframe with auto-resize via postMessage
  • Configurable theme (light/dark), accent color, min height
  • Callbacks: data-on-submit, data-on-load for parent page integration
  • WordPress plugin included ([dfw_form] shortcode + Gutenberg block)
  • Admin embed code panel with copy-to-clipboard snippets
  • Inline success state — no redirects, iframe stays self-contained

See Embedding Guide.

💳 Payment Collection

Collect payments as part of the form submission flow:

  • Pluggable provider architecture: PaymentProvider ABC, provider registry, PaymentResult dataclass
  • Two flow types: INLINE (payment form on your site, e.g. Stripe Elements) and REDIRECT (external payment page)
  • Built-in Stripe provider using PaymentIntents with automatic payment methods
  • PaymentRecord model tracks full payment lifecycle (pending → completed/failed/refunded)
  • Configurable per form: provider, amount (fixed or from field), currency, description template
  • Custom providers self-register via register_provider() in AppConfig.ready()

See Payment System Guide.

📋 Shared Option Lists

Define reusable choice lists shared across forms:

  • SharedOptionList model with name, slug, items (JSON array of strings or value/label objects)
  • shared_option_list FK on FormField overrides inline choices for select, radio, multiselect, checkboxes
  • Choice resolution priority: database prefill → shared option list → inline choices
  • Update a list once, every referencing field updates immediately
  • Form builder UI with shared list dropdown on choice-based fields

See Shared Option Lists Guide.

🔗 Dependent Workflows

Workflows that wait for other workflows to complete before starting:

  • start_trigger = "on_all_complete" on WorkflowDefinition
  • Enables convergence patterns: parallel tracks must all finish before a final review step
  • Peer-level relationship (not parent/child like sub-workflows)
  • Complements sub-workflows — both can coexist on the same form

See the Dependent Workflows section of the Workflows Guide.

🧮 Calculated / Formula Fields

Auto-compute field values from other field inputs:

  • field_type = "calculated" with a formula template string (e.g. {first_name} {last_name})
  • Live client-side evaluation updates the read-only field as the user types
  • Authoritative server-side re-evaluation on submit prevents tampering
  • Available in both regular form submission and approval step forms

See Calculated Fields Guide.

📊 Spreadsheet Upload Fields

Accept CSV or Excel files as structured form input:

  • field_type = "spreadsheet" with accept .csv, .xls, .xlsx
  • Parsed and stored as {"headers": [...], "rows": [{...}, ...]} in form_data
  • Available during initial submission and approval step forms

🔌 Configurable Prefill Sources

Populate form fields automatically from reusable PrefillSource records:

  • User modeluser.email, user.first_name, user.username, etc.
  • LDAP / Active Directory — any LDAP attribute (department, title, manager, custom)
  • External databases — schema/table/column lookup with template support for multi-column composition
  • Custom database queries — reference a named query via database_query_key
  • System valuescurrent_date, current_time

⚡ Post-Submission Actions

Automatically run side-effects after a submission event:

Trigger Description
on_submit Runs immediately on form submission
on_approve Runs when the submission is approved
on_reject Runs when the submission is rejected
on_complete Runs when the entire workflow completes

Action types: email, database, ldap, api, custom

Features:

  • Conditional execution with 10 operators (equals, not_equals, greater_than, less_than, contains, not_contains, is_empty, is_not_empty, is_true, is_false, plus date comparisons)
  • Automatic retries with configurable max_retries
  • Execution ordering for dependent actions
  • Idempotent locking (is_locked) to prevent double-execution
  • Full execution logging via ActionExecutionLog
  • Pluggable handler architecture — register custom handlers via FORMS_WORKFLOWS_CALLBACKS setting or register_handler() API; use short names in the admin instead of full Python paths

🔄 Cross-Instance Form Sync

Move form definitions between environments from the Django Admin:

  • Pull from Remote — connect to a configured remote instance and import selected forms
  • Push to Remote — select forms and push to any destination
  • Import / Export JSON — portable .json snapshots
  • Conflict modesupdate, skip, or new_slug
  • FORMS_SYNC_REMOTES setting — pre-configure named instances (URL + token)
  • HTTP endpoints protected by Bearer token for CI/scripted use

📁 Managed File Uploads

  • FileUploadConfig per form definition (allowed extensions, max size)
  • ManagedFile records with approval/rejection/supersede lifecycle
  • Version tracking with is_current flag

🔒 Enterprise-Ready Security

  • LDAP/Active Directory authentication with auto-sync of profile attributes
  • SSO integration (SAML, OAuth) with attribute mapping to UserProfile
  • Role-based access — four permission tiers on FormDefinition:
    • submit_groups — can see and submit the form
    • view_groups — prerequisite gate for form access
    • reviewer_groups — read-only view of all submissions and approval history
    • admin_groups — full administrative view of all submissions
  • Group-based approval routing via WorkflowStage.approval_groups
  • Complete audit logging (AuditLog — who, what, when, IP address)
  • Public / anonymous forms — mark any form as requires_login=False and anonymous users can submit it; IP-based rate limiting prevents abuse
  • UserProfile auto-created on first login with LDAP/SSO sync

Quick Start

Installation

pip install django-forms-workflows

Setup

  1. Add to INSTALLED_APPS:
INSTALLED_APPS = [
    # ...
    'crispy_forms',
    'crispy_bootstrap5',
    'django_forms_workflows',
]

CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
  1. Include URLs and run migrations:
# urls.py
urlpatterns = [
    path('forms/', include('django_forms_workflows.urls')),
]
python manage.py migrate django_forms_workflows
  1. Create your first form in Django Admin!

Optional Settings

FORMS_WORKFLOWS = {
    # Branding — replaces "Django Forms Workflows" across all templates
    "SITE_NAME": "Acme Corp Workflows",

    # LDAP attribute sync on every login
    "LDAP_SYNC": {
        "enabled": True,
        "attributes": {
            "department": "department",
            "title": "title",
            "employee_id": "extensionAttribute1",
        },
    },
}

# Cross-instance form sync
FORMS_SYNC_API_TOKEN = "shared-secret"
FORMS_SYNC_REMOTES = {
    "production": {
        "url": "https://prod.example.com/forms-sync/",
        "token": "prod-token",
    },
}

# Custom callback handlers — register by short name instead of full Python paths
# These names can be used in PostSubmissionAction.custom_handler_path
FORMS_WORKFLOWS_CALLBACKS = {
    "id_photo_copy": "myapp.handlers.IDPhotoHandler",
    "sync_to_erp": "myapp.handlers.ERPSyncHandler",
}

# Context processor — injects site_name into every template
TEMPLATES = [
    {
        "OPTIONS": {
            "context_processors": [
                # ... standard processors ...
                "django_forms_workflows.context_processors.forms_workflows",
            ]
        }
    }
]

Architecture

graph TB
    subgraph UI["User Interface"]
        FB["Form Builder<br/>(Admin)"]
        FV["Form Viewer<br/>(End User)"]
        AU["Approval UI<br/>(Approvers)"]
    end

    subgraph Core["Django Forms Workflows"]
        FD["FormDefinition<br/>+ FormField"]
        WF["WorkflowDefinition<br/>+ WorkflowStage"]
        PS["PrefillSource"]
        PA["PostSubmissionAction<br/>+ Executor"]
        SYNC["Sync API<br/>(Push/Pull)"]
    end

    subgraph External["External Systems"]
        AD["LDAP / AD"]
        DB["External<br/>Databases"]
        API["REST APIs"]
        SSO["SSO<br/>(SAML/OAuth)"]
    end

    FB --> FD
    FV --> FD
    AU --> WF
    FD --> PS
    FD --> PA
    FD --> SYNC
    PS --> AD
    PS --> DB
    PA --> DB
    PA --> AD
    PA --> API
    SSO --> Core
Loading

Use Cases

  • HR — Onboarding, time-off requests, expense reports, status changes
  • IT — Access requests, equipment requests, change management
  • Finance — Purchase orders, invoice approvals, budget requests
  • Education — Student applications, course registrations, facility booking
  • Healthcare — Patient intake, referrals, insurance claims
  • Government — Permit applications, FOIA requests, citizen services

Comparison

Feature Django Forms Workflows Crispy Forms FormStack Django-Formtools
Database-driven forms
No-code form creation
Self-hosted
Multi-stage approval workflows ⚠️
Sub-workflows
Post-submission actions ⚠️
External data prefill ⚠️
REST API (Bearer token)
Bulk export (Excel / CSV)
Cross-instance sync
LDAP/AD + SSO integration
Managed file uploads
Audit trail
Open source

Requirements

  • Python 3.10+
  • Django 5.2+
  • PostgreSQL, MySQL, or SQLite (PostgreSQL recommended for production)
  • Optional: Celery 5.0+ with Redis/Valkey for background task processing
  • Optional: openpyxl for Excel spreadsheet field support (pip install django-forms-workflows[excel])
  • Optional: django-auth-ldap for LDAP/AD integration (pip install django-forms-workflows[ldap])
  • Optional: WeasyPrint for PDF export (pip install django-forms-workflows[pdf])

Testing

cd django-forms-workflows
pip install pytest pytest-django
python -m pytest tests/ -v

The test suite covers models, forms, workflow engine (including dynamic assignees, conditional stages, multi-workflow parallel tracks, sub-workflows), sync API, post-submission action executor, views, signals, conditions, and utilities — 298 tests.

Contributing

We welcome contributions! Please see CONTRIBUTING.md for details.

License

GNU Lesser General Public License v3.0 (LGPLv3) — see LICENSE for details.

Support

Roadmap

See docs/ROADMAP.md for the full prioritized roadmap with rationale and implementation notes.

✅ Delivered (through v0.48)

  • Database-driven form definitions with 25+ field types
  • Dynamic form rendering with Crispy Forms + Bootstrap 5
  • Multi-stage approval workflows (any/all/sequence logic per stage)
  • Conditional workflow & stage trigger logic
  • Dynamic individual assignee resolution (email / username / full name / LDAP)
  • Send Back for Correction (return to any prior stage without terminating)
  • Sub-workflow support (spawn N child instances from a parent)
  • Calculated / formula fields with live client-side evaluation
  • Spreadsheet upload fields (CSV, XLS, XLSX)
  • LDAP/AD integration with profile sync
  • SSO attribute mapping (SAML/OAuth)
  • Configurable prefill sources (user, LDAP, database, API, system values)
  • Post-submission actions with conditional execution, ordering & retries
  • Cross-instance form sync (push/pull/JSON import-export)
  • Managed file uploads with approval lifecycle and S3/Spaces presigned URLs
  • Conditional field visibility (client-side JS, no page reload)
  • Form templates and cloning
  • Nested category hierarchy with group-based access control
  • WeasyPrint PDF export with multi-column layout
  • Column-picker approval inbox with DataTables
  • Complete audit logging (who, what, when, IP)
  • Configurable site branding via FORMS_WORKFLOWS['SITE_NAME']
  • Comprehensive test suite (298 tests)
  • REST API — Bearer-token authenticated endpoints: list forms, fetch field schema, submit (JSON or multipart, including ?draft=1), poll submission status; OpenAPI 3.0 schema + Swagger UI
  • Bulk export — Excel and CSV export of submission data from the approval inbox (allow_bulk_export / allow_bulk_pdf_export per workflow)
  • Four-tier RBAC — submit_groups, view_groups, reviewer_groups (read-only submission history), admin_groups (full submission view) with consistent enforcement across all list and detail views
  • Auto-save with configurable interval; Save Draft bypasses required-field validation without storing browser internals (CSRF token, button names)
  • Signature field type (drawn or typed) — v0.45.0
  • Form versioning — ChangeHistory tracking, sync API snapshots, admin diff viewer action — v0.45.0
  • Advanced reporting dashboard (submission analytics, approval times, bottleneck stages) — v0.46.0
  • Settings-based callback handler registry (FORMS_WORKFLOWS_CALLBACKS) — register custom handlers by name instead of hardcoding Python paths in the database — v0.48.0
  • First-class workflow webhooks with HMAC signing, async retry/backoff, admin configuration, delivery logs, cloning, and sync support

🚧 Near-term (next 1–3 releases)

📋 Planned (medium-term)

Credits

Built with ❤️ by the Django community.

Special thanks to: