Django app for building long-running, interactive, and stateful AI workflows using LangGraph
Project description
Graflow Django
This is a Django app plus a reference Django project that has a simple flows API built on top of Django REST Framework and LangGraph. It's A WAY to build and run stateful, long-running, and interactive workflows (flows) in a multi-tenant environment.
Highlights
- Flows API to get flow types, CRUD operation on flows, stats, resume, and cancellation endpoints.
- User Interaction based on LangGraph's human-in-the-loop.
- Persistence with pluggable node-cache, checkpointer and store for long-term memory (based on PostgreSQL).
- Django admin for inspecting flow state and store/cache tables using Django ORM (models).
- Flow Definition and Registration via settings or programmatically
- Extensive tests covering API behavior, graph execution, and storage abstractions.
Project Layout
graflow-django/
├── graflow/ # Reusable app with models, API, graphs, and storage backends
├── myflows/ # Reference Django project wiring the app + DRF
├── manage.py # Standard Django entry point
├── pyproject.toml # Project metadata, dependencies, tooling config
├── README.md # You are here
└── LICENCE # Project licence (MIT-compatible)
Requirements
You need Python 3.12+ (project currently targets 3.13). You can install all required Python packages using pip command. See Quick Start section. You also need API keys if you are using LLM calls in your flows.
Quick Start
To get the idea, you can run this Django project like other Django project. If you want to use the Django app as a 3rd party app in your own Django project, see the Configuration sectioin.
git clone https://github.com/ulern-com/graflow-django.git
cd graflow-django
python -m venv .venv
source .venv/bin/activate
# Install with PostgreSQL support (required for production)
pip install -e ".[dev,postgres]"
# Start PostgreSQL (using Docker Compose)
docker-compose up -d
# Or use your own PostgreSQL instance and configure DB_* environment variables
# Create .env file with your database credentials:
# DB_NAME=myflows
# DB_USER=postgres
# DB_PASSWORD=postgres
# DB_HOST=127.0.0.1 # Use 127.0.0.1 (not localhost) to avoid IPv6 connection issues
# DB_PORT=5432
python manage.py migrate
python manage.py createsuperuser # optional, for admin access
python manage.py runserver
Visit http://localhost:8000/api/graflow/flows/ to explore the DRF browsable API.
Note: This project requires PostgreSQL to demonstrate the full benefits of graflow's storage, cache, and checkpoint implementations. SQLite is not supported for the Django persistence backend.
Also note that to run a flow with LLM call, you need to set your own API key in the environment.
Configuration
All settings of this Django project live in myflows/settings.py. Environment-specific overrides can be provided via .env.
Database Configuration
The project uses PostgreSQL by default. Configure it via environment variables:
| Variable | Default | Description |
|---|---|---|
DB_NAME |
myflows |
PostgreSQL database name |
DB_USER |
postgres |
PostgreSQL user |
DB_PASSWORD |
postgres |
PostgreSQL password |
DB_HOST |
127.0.0.1 |
PostgreSQL host (use 127.0.0.1, not localhost, to avoid IPv6 issues) |
DB_PORT |
5432 |
PostgreSQL port |
DB_SSLMODE |
disable |
SSL mode for connection |
Graflow Configuration
| Variable | Default | Description |
|---|---|---|
GRAFLOW_APP_NAME |
myflows |
Logical namespace for graphs and flows |
GRAFLOW_PERSISTENCE_BACKEND |
django |
django (requires PostgreSQL) or memory for testing |
GRAFLOW_NODE_CACHE_TTL |
2592000 (30 days) | Cache TTL for LangGraph node results |
GRAFLOW_REQUIRE_AUTHENTICATION |
True |
Require authentication for API access |
| Tests default to the in-memory backend so they run without PostgreSQL. Production must use PostgreSQL to enable the Django store, cache, and checkpointer implementations. |
Flow Type Registration
Flow types (graphs) are registered via the Django admin interface using the FlowType model. This provides a database-backed registry that supports multi-tenancy, versioning, and per-flow-type permissions/throttling.
To register a flow type:
- Go to the Django admin interface
- Navigate to "Flow Types"
- Click "Add Flow Type"
- Fill in the required fields:
app_name: Application name (for multi-tenancy)flow_type: Type identifier (e.g., "hello_world")version: Version string (e.g., "v1", "1.0.0")builder_path: String path to builder function (e.g., "myapp.graphs:build_graph")state_path: String path to state class (e.g., "myapp.graphs:GraphState")is_latest: Whether this is the latest versionis_active: Whether this flow type is active
You can also configure permissions and throttling per flow type by specifying class paths (e.g., "myapp.permissions:CustomPermission"). See the Permissions and Throttling section below for details.
Permissions and Throttling
Graflow supports fine-grained, per-flow-type permissions and throttling for access control and rate limiting. Each FlowType can have separate permission and throttle classes for CRUD operations (list, create, retrieve, destroy, cancel) and resume operations.
Quick Overview
Permissions control who can access which flows:
- Default:
IsAuthenticatedfor both CRUD and resume operations - Can be customized per flow type via
crud_permission_classandresume_permission_class - Supports custom permission classes for subscription tiers, user roles, flow ownership, etc.
Throttling controls how frequently users can perform operations:
- Default: 100 requests/hour for creation, 300 requests/hour for resume
- Can be customized per flow type via
crud_throttle_classandresume_throttle_class - Supports custom throttle classes for tiered access (premium vs. free users)
Configuration
Configure permissions and throttling via Django admin or programmatically when creating FlowType instances. Specify class paths in format module.path:ClassName (e.g., myapp.permissions:SubscriptionPermission).
Example:
flow_type = FlowType.objects.create(
app_name="myapp",
flow_type="premium_workflow",
version="v1",
builder_path="myapp.graphs:build_premium_workflow",
state_path="myapp.graphs:PremiumWorkflowState",
is_latest=True,
crud_permission_class="myapp.permissions:SubscriptionPermission",
resume_permission_class="myapp.permissions:SubscriptionPermission",
crud_throttle_class="myapp.throttling:PremiumUserThrottle",
resume_throttle_class="myapp.throttling:PremiumUserThrottle",
)
For detailed documentation, examples, and best practices, see docs/PERMISSIONS_AND_THROTTLING.md.
Working with Flows
- Register flow types via the Django admin interface (see "Flow Type Registration" section above).
- Create flows by POSTing to
/api/graflow/flows/with aflow_typeand optional state payload. - Resume flows via
/api/graflow/flows/<id>/resume/when user input is required. - Inspect stats at
/api/graflow/flows/stats/or fetch the most recent flow via/api/graflow/flows/most-recent/. - List available flow types at
/api/graflow/flow-types/.
All endpoints require authentication by default; DRF session auth is enabled. You can disable authentication for demo/testing by setting GRAFLOW_REQUIRE_AUTHENTICATION = False.
Cancellation semantics: POST /flows/<id>/cancel/ enforces business rules and
returns 400 if the flow is already completed/failed/cancelled. DELETE /flows/<id>/
is an idempotent soft delete that always succeeds by marking the flow cancelled so it
disappears from subsequent responses. Pick the endpoint that matches your UX needs.
Persistence For Stateful Flows
Need to understand how the Django-based checkpointer, store, and cache work? Head over to graflow/storage/README.md. It documents:
- How
DjangoSaver,DjangoStore, andDjangoCachewrap LangGraph’s PostgreSQL persistence layers - Which Django models map to LangGraph tables
- When to enable the Django backend vs. in-memory persistence
Referencing that file keeps these docs close to the storage code so they stay accurate.
API Documentation
-
See
graflow/api/README.mdfor a high-level overview of every endpoint plus regeneration instructions. -
The full OpenAPI contract lives at
docs/flows-api.schema.yml. Regenerate it after API changes with:source .venv/bin/activate python manage.py spectacular --file docs/flows-api.schema.yml --format openapi
Commit the updated schema (and optional HTML exports) so API changes are visible in PRs without running the dev server.
Testing
Make sure you have the DB running before running the tests. You can use:
docker-compose up -d
Then
just test
Or with coverage:
just test-cov
The suite spins up a fully configured Django test environment, registers sample graphs, and covers:
- API contract tests (
graflow/tests/test_flows_api.py) - LangGraph integrations
- Cache / store / checkpoint adapters
Tests that require PostgreSQL are automatically skipped when running against SQLite (see test_checkpoint.py and test_store.py).
Development Tips
- Format code:
just format(usesblack) - Lint code:
just lint(usesruff) - Fix linting issues:
just lint-fix - Type check:
just type-check(usesmypy) - Run all checks:
just check(lint + type-check) - Visualize graphs:
python manage.py visualize_graph --flow-type your_flow(Graphviz recommended) - Refer to
graflow/tests/factories.pyfor sample model factories and to bootstrap seed data
See justfile for all available commands. Install just from https://github.com/casey/just.
Contributing
- Fork the repo and create a feature branch.
- Install dev dependencies:
pip install -e ".[dev]". - Run
just checkandjust testto ensure everything passes before opening a PR. - Describe your change clearly and link related issues.
We welcome bug reports, feature requests, docs updates, and test improvements.
Licence
See LICENCE for the full legal text. Contributions are accepted under the same terms.
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 Distribution
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_graflow-0.3.0.tar.gz.
File metadata
- Download URL: django_graflow-0.3.0.tar.gz
- Upload date:
- Size: 43.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b50086634df82df43535ee76194a13b408e78713e8bd909dcb20612a723eff8c
|
|
| MD5 |
a7cc7a2b70cb1090dd3e5285f6dfc294
|
|
| BLAKE2b-256 |
75140287103293d029150fb8558eecb15af5cfdd2df2e36e05595bb1ca5648e5
|
File details
Details for the file django_graflow-0.3.0-py3-none-any.whl.
File metadata
- Download URL: django_graflow-0.3.0-py3-none-any.whl
- Upload date:
- Size: 50.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.13.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
865bcf744aef70f633b244c0e5cdbb79c57b9f4c908e227fe525e8ccddd980ec
|
|
| MD5 |
48e77a26c08c177eb4eb5ab977502ed1
|
|
| BLAKE2b-256 |
859edb85e68f90a385e1021ba24494df9db6d9d6e4657e969e2dea1aabf5c792
|