Skip to main content

django-joist

A live database structure viewer for Django. Joist introspects your live schema and renders it as a scrollable, zoomable ER diagram right inside your app, so you can see how tables actually connect without opening a DB client. It reads structure only — tables, columns, keys, indexes, foreign keys; row data is never queried or exposed.

django-joist is a Django port of the concept implemented by Laravel Truss (MIT, Alberto Arena), which inspired it. The name, branding and Django wiring are original; selected front-end code is adapted under MIT with attribution.

Features

  • Live ER diagram of your database, rendered with Mermaid — self-hosted, no CDN, no build step.
  • Focus mode: a table and its foreign-key neighbours, with a searchable picker that stays usable on schemas with hundreds of tables.
  • Filter by table name; toggle native DB types against Django-style labels.
  • Map-style pan and zoom, auto-fit with a legible floor, plus a Fit button.
  • Exports: PNG/SVG from the browser; DBML, JSON, CSV, Markdown data dictionary, Mermaid, or a token-trimmed llm format — from the dashboard or from CI with manage.py joist_export. Deterministic: the same schema always produces the same bytes, so joist_export --check fails the build when a committed schema file drifts.
  • Feed your real structure to a coding agent as grounding context: annotations for business meaning, --compact to trim tokens, --focus to narrow to one neighbourhood. Only the schema is read — row data is never touched.
  • Schema diff: what changed since the last migration, in the dashboard's Changes panel and via manage.py joist_diff.
  • Schema doctor: manage.py joist_doctor reviews the structure for problems (missing primary keys, unindexed foreign keys, duplicate indexes, risky types) — deterministic, structure-only, safe in CI, with --fail-on exit codes; the same findings power the dashboard's Health panel.
  • Multiple databases: list aliases under JOIST["connections"] and switch diagrams from the toolbar, each scoped to its own database.
  • Light/dark "blueprint" theme, or bring your own: a handful of semantic colour/font knobs re-skin the whole dashboard, served as a same-origin stylesheet (CSP-safe, no inline styles).
  • Rebuilds itself: the cached snapshot refreshes after every migrate and degrades gracefully when the cache store is unreachable.
  • Production-safe by design: routes answer 404 unless enabled, denials never confirm the dashboard exists, and excluded tables are filtered server-side so their structure never reaches the browser.

Installation

pip install django-joist

Add the app and mount the dashboard:

# settings.py
INSTALLED_APPS = [
    ...,
    "django_joist",
]

# urls.py
from django.urls import include, path

urlpatterns = [
    ...,
    path("joist/", include("django_joist.urls")),
]

Requires Python 3.13+ and Django 5.2+. No migrations, no models, no collectstatic needed (assets are served by the package, gated with the rest of the dashboard). The dashboard HTML is a template shipped inside the app, so your TEMPLATES must keep "APP_DIRS": True for django_joist (the default in django-admin startproject); if you disabled it, add the package's template directory to DIRS.

Quick start

By default Joist is enabled when DEBUG = True. Start your dev server and visit /joist/.

To run Joist gated on staging or production, set both switches:

JOIST = {
    "enabled": True,
    "authorization": {
        "allowed_emails": ["ada@example.com", "grace@example.com"],
    },
}

Outside DEBUG the shipped default authorizer admits only allow-listed emails and fails closed on an empty list. To authorize by role instead, point authorization.callable at your own request -> bool (a callable or a dotted path); it fully replaces the default. Denials always return 404.

Your project's AuthenticationMiddleware must run for the mounted URLs (the normal case). Joist's own guard is part of the views and cannot be configured away.

Command line

python manage.py joist_show                 # the structure as a terminal table
python manage.py joist_open                 # print/open the dashboard URL
python manage.py joist_rebuild              # rebuild the cached snapshot (CI)
python manage.py joist_diff                 # what changed since the last migration
python manage.py joist_doctor               # structure review; exits non-zero on findings
python manage.py joist_export               # DBML to stdout by default
python manage.py joist_export --format=json --output=docs/schema.json
python manage.py joist_export --format=dbml --output=docs/schema.dbml --check  # CI drift check
python manage.py joist_export --tables=orders,order_lines --focus=orders --depth=1 --compact

joist_doctor --format=json and --fail-on=warning make it a CI gate; joist_export --check regenerates, compares, writes nothing and exits 1 on drift (2 on usage errors), so a migration that changes the schema without refreshing the committed file fails the build.

As AI context

The same export doubles as grounding context for a coding agent, so it stops inventing columns:

python manage.py joist_export --format=llm          # dense, token-trimmed plaintext
python manage.py joist_export --compact             # drop defaults and non-unique indexes
python manage.py joist_export --focus=orders --depth=1

Annotations add the business meaning a type cannot — declare them in settings under JOIST["annotations"] (per-table, per-column, global notes) or let Joist read native database comments (Postgres/MySQL) by keeping "database" in annotations["source"]. The llm format and Markdown/DBML all render annotations; --no-annotations strips them.

Programmatically, the builder is immutable and mirrors the CLI byte-for-byte:

from django_joist import snapshot

text = (
    snapshot()
    .only(["orders", "order_lines"])
    .focus("orders", depth=1)
    .compact()
    .to_dbml()
)

Configuration

Everything lives in one JOIST dict; unset keys keep their defaults (nested dicts merge key-by-key). The common knobs:

Key Purpose
enabled Master switch; defaults to DEBUG. Off = every route 404s
connections Visualizable database aliases + per-alias overrides, e.g. {"analytics": {"excluded_tables": [...]}}; empty = just default
excluded_tables Hidden server-side (never sent to the browser). Django bookkeeping tables are pre-listed
authorization.callable / .allowed_emails Who may view outside DEBUG; a custom callable replaces the email allow-list
cache.ttl / cache.alias Snapshot cache (seconds, <= 0 = forever) and which CACHES entry to use
diagram.type_labels native (default) or django short labels
diagram.mermaid_url Point at your own copy/CDN; default self-hosts from the gated asset route
focus.default_depth FK-neighbour hops shown on focus
large_schema.warn_above Table count that triggers the "use focus/filter" hint
diff.enabled / diff.dir Schema-diff switch and where the structure-only baseline lives (default BASE_DIR/var/joist)
doctor.* Preset, per-rule severity/enable, ignore patterns, fail_on, dashboard panel switches
annotations.* Global notes, per-table/per-column meaning, comment sources
theme.* Semantic colour/font knobs for both light and dark
base_url Used by joist_open to build a browsable URL

The baseline file under diff.dir is the only thing Joist writes to disk; it is derived and safe to delete — worth gitignoring alongside var/.

The no-data promise

Structure is the CREATE TABLE definition: tables, columns (name, native type, nullability, defaults), primary keys, indexes, foreign keys with referential actions, and native comments. Row contents are never queried — not by the dashboard, the API, the CLI, or the doctor. Config excluded_tables are stripped server-side, so an excluded table never reaches the client, the diff, or an export.

Development

pip install -e ".[dev]"
python -m pytest

License

MIT. See LICENSE (includes the attribution to Laravel Truss). Vendored assets carry their own licenses (Mermaid MIT, IBM Plex Mono SIL OFL) under src/django_joist/static/joist/.

Metadata

Release files for django-joist 0.1.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 django-joist 0.1.0
File Size Uploaded Provenance Actions
django_joist-0.1.0.tar.gz 1.1 MB With provenance Details for django_joist-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for django-joist 0.1.0
File Interpreter ABI Platform Actions
django_joist-0.1.0-py3-none-any.whl Python 3 none any Details for django_joist-0.1.0-py3-none-any.whl

Total release size: 2.3 MB

Release files / django_joist-0.1.0.tar.gz

Download URL django_joist-0.1.0.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
edd7909c28429aa65f92141063b14981d37f3eddac2ddd4c94ecf6c7d9082aa6
BLAKE2b-256 checksum
How to use checksums
7cd57e26077118d0e4acd0a7e47e0214f2da6c3f1a75efdcf119aec47dcf6fe6
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 11, 2026.

Transparency log

Release files / django_joist-0.1.0-py3-none-any.whl

Download URL django_joist-0.1.0-py3-none-any.whl
Size 1.2 MB
Tags Python 3
SHA-256 checksum
How to use checksums
7c2a209fff1c02add3b6dbbea65765bbbb07d806f07f13565cfab94868236938
BLAKE2b-256 checksum
How to use checksums
e3064af0df6c9e8b4fedd019fcdc913cb995f9210d90a2dcc5177b91b16a87e8
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 11, 2026.

Transparency log

Security for django-joist 0.1.0

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.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for django_joist-0.1.0.tar.gz

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 11, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

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