https://github.com/opensensor/django-forms-workflows
An enterprise-grade Django app: database-driven form builder with approval workflows and external data integration. It bridges the gap between simple form libraries (like Crispy Forms) and expensive SaaS solutions (like JotForm, Formstack).
https://github.com/opensensor/django-forms-workflows
django-forms
Last synced: 2 months ago
JSON representation
An enterprise-grade Django app: database-driven form builder with approval workflows and external data integration. It bridges the gap between simple form libraries (like Crispy Forms) and expensive SaaS solutions (like JotForm, Formstack).
- Host: GitHub
- URL: https://github.com/opensensor/django-forms-workflows
- Owner: opensensor
- License: lgpl-3.0
- Created: 2025-10-31T01:27:40.000Z (8 months ago)
- Default Branch: main
- Last Pushed: 2026-04-10T20:59:19.000Z (2 months ago)
- Last Synced: 2026-04-10T22:15:04.371Z (2 months ago)
- Topics: django-forms
- Language: Python
- Homepage:
- Size: 2.21 MB
- Stars: 9
- Watchers: 1
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
- Contributing: CONTRIBUTING.md
- License: LICENSE
- Roadmap: docs/ROADMAP.md
Awesome Lists containing this project
README
# Django Forms Workflows
**Enterprise-grade, database-driven form builder with multi-stage approval workflows, external data integration, and cross-instance sync**
[](https://www.gnu.org/licenses/lgpl-3.0)
[](https://www.python.org/downloads/)
[](https://www.djangoproject.com/)
[](https://github.com/opensensor/django-forms-workflows)
## 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 `` 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](docs/WORKFLOWS.md), [Visual Workflow Builder](docs/VISUAL_WORKFLOW_BUILDER.md), [Dynamic Assignees](docs/DYNAMIC_ASSIGNEES.md), [Send Back for Correction](docs/SEND_BACK.md), [Notifications](docs/NOTIFICATIONS.md), and [Workflow Webhooks](docs/WEBHOOKS.md).
### đ 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](docs/SUB_WORKFLOWS.md) 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](docs/EMBEDDING.md).
### đŗ 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](docs/PAYMENTS.md).
### đ 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](docs/SHARED_OPTION_LISTS.md).
### đ 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](docs/WORKFLOWS.md#dependent-workflows) 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](docs/CALCULATED_FIELDS.md).
### đ 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 model** â `user.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 values** â `current_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 modes** â `update`, `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
```bash
pip install django-forms-workflows
```
### Setup
1. Add to `INSTALLED_APPS`:
```python
INSTALLED_APPS = [
# ...
'crispy_forms',
'crispy_bootstrap5',
'django_forms_workflows',
]
CRISPY_ALLOWED_TEMPLATE_PACKS = "bootstrap5"
CRISPY_TEMPLATE_PACK = "bootstrap5"
```
2. Include URLs and run migrations:
```python
# urls.py
urlpatterns = [
path('forms/', include('django_forms_workflows.urls')),
]
```
```bash
python manage.py migrate django_forms_workflows
```
3. Create your first form in Django Admin!
### Optional Settings
```python
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
```mermaid
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
```
## 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
```bash
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](CONTRIBUTING.md) for details.
## License
GNU Lesser General Public License v3.0 (LGPLv3) â see [LICENSE](LICENSE) for details.
## Support
- đ [Documentation](https://django-forms-workflows.readthedocs.io/)
- đŦ [Discussions](https://github.com/opensensor/django-forms-workflows/discussions)
- đ [Issue Tracker](https://github.com/opensensor/django-forms-workflows/issues)
## Roadmap
See [docs/ROADMAP.md](docs/ROADMAP.md) for the full prioritized roadmap with rationale and implementation notes.
### â
Delivered (through v0.48)
- [x] Database-driven form definitions with 25+ field types
- [x] Dynamic form rendering with Crispy Forms + Bootstrap 5
- [x] Multi-stage approval workflows (any/all/sequence logic per stage)
- [x] Conditional workflow & stage trigger logic
- [x] Dynamic individual assignee resolution (email / username / full name / LDAP)
- [x] Send Back for Correction (return to any prior stage without terminating)
- [x] Sub-workflow support (spawn N child instances from a parent)
- [x] Calculated / formula fields with live client-side evaluation
- [x] Spreadsheet upload fields (CSV, XLS, XLSX)
- [x] LDAP/AD integration with profile sync
- [x] SSO attribute mapping (SAML/OAuth)
- [x] Configurable prefill sources (user, LDAP, database, API, system values)
- [x] Post-submission actions with conditional execution, ordering & retries
- [x] Cross-instance form sync (push/pull/JSON import-export)
- [x] Managed file uploads with approval lifecycle and S3/Spaces presigned URLs
- [x] Conditional field visibility (client-side JS, no page reload)
- [x] Form templates and cloning
- [x] Nested category hierarchy with group-based access control
- [x] WeasyPrint PDF export with multi-column layout
- [x] Column-picker approval inbox with DataTables
- [x] Complete audit logging (who, what, when, IP)
- [x] Configurable site branding via `FORMS_WORKFLOWS['SITE_NAME']`
- [x] Comprehensive test suite (298 tests)
- [x] 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
- [x] Bulk export â Excel and CSV export of submission data from the approval inbox (`allow_bulk_export` / `allow_bulk_pdf_export` per workflow)
- [x] 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
- [x] Auto-save with configurable interval; Save Draft bypasses required-field validation without storing browser internals (CSRF token, button names)
- [x] Signature field type (drawn or typed) â v0.45.0
- [x] Form versioning â ChangeHistory tracking, sync API snapshots, admin diff viewer action â v0.45.0
- [x] Advanced reporting dashboard (submission analytics, approval times, bottleneck stages) â v0.46.0
- [x] Settings-based callback handler registry (`FORMS_WORKFLOWS_CALLBACKS`) â register custom handlers by name instead of hardcoding Python paths in the database â v0.48.0
- [x] 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:
- Logan Nickerson for his time spent testing and helping with business requirements
- [Django Crispy Forms](https://github.com/django-crispy-forms/django-crispy-forms)
- [Celery](https://github.com/celery/celery)
- [django-auth-ldap](https://github.com/django-auth-ldap/django-auth-ldap)