English · Русский · Español · 中文

Django ORM Lens

See your entire Django schema — in your editor, in your terminal, and from your AI agent.

Every app. Every model. Every field. Every relationship. Grouped, navigable, and one keystroke away from a live ER diagram.

PyPI Python Django versions CI Downloads License

Install on VS Code Install on Open VSX Docker GHCR


🎯 Pick your path

Django ORM Lens ships as three distributions on one core — pick the one that matches your workflow. Each takes under 60 seconds.

Editor user (VS Code / Cursor / Windsurf / VSCodium / code-server / Gitpod): install the extension → open any Django project → sidebar tree + ER diagram appear.

code --install-extension frowningdev.django-orm-lens          # VS Code, Cursor, Windsurf
codium --install-extension frowningdev.django-orm-lens        # VSCodium, code-server (via Open VSX)

Terminal / CI user: install from PyPI → run django-orm-lens in any directory that contains Django apps.

pip install django-orm-lens
django-orm-lens               # welcome + commands
django-orm-lens scan          # scan cwd for apps and models

AI coding agent user (Cursor / Aider / Continue / Zed): install with MCP extras → add one JSON block to your client config.

pip install "django-orm-lens[mcp]"

Then the MCP config snippet in the Integrations section below. Point DJANGO_ORM_LENS_ROOT at your Django project's absolute path.


📊 Traction

GitHub stars Forks PyPI monthly Total downloads Marketplace rating Contributors Last commit

MCP Registry Smithery Glama awesome-mcp-servers mcp.so

If the tool saves you a grep next time you touch a strange Django project — a star helps others find it.

📈 Star growth


⚡ Install

VS Code / Cursor / Windsurf (VS Code Marketplace):

code --install-extension frowningdev.django-orm-lens

VSCodium / code-server / Gitpod / any OSS Code fork (Open VSX):

codium --install-extension frowningdev.django-orm-lens

Or search Django ORM Lens in the Extensions view — same publisher frowningdev on both registries.

Terminal & AI coding agents:

pip install django-orm-lens              # CLI only
pip install "django-orm-lens[mcp]"       # + MCP server for AI agents

Requires Python 3.9+. Zero runtime dependencies for the CLI.

Docker (v0.6+):

docker run --rm -v "$PWD:/workspace" ghcr.io/frowningdev/django-orm-lens scan --path .

Multi-arch (amd64 + arm64). No Python required on the host. Good for CI and one-off audits.

🎯 The problem

Works offline. Works on a broken venv. Works on someone else's laptop. Works in CI.

You open a Django project. It has 20 apps. You need to answer a simple question:

"Which app owns the Order model, and how is it connected to User?"

Today, that means: Ctrl+P, "models", scroll through 30 hits, open five files, Ctrl+F for class Order, read through 400 lines of ForeignKey('otherapp.Something') strings, try to remember what you learned two files ago.

Half a day gone. Every time. On every project.

✨ With Django ORM Lens

📚 A tree of everything

Every app → every model → every field → every Meta option. Grouped by application, sorted alphabetically, expandable.

Icons distinguish CharField from ForeignKey from ManyToManyField at a glance.

🕸️ A live ER diagram

One command opens a Mermaid entity-relationship diagram of your entire schema. Watch it redraw as you edit. Export to SVG.

ForeignKey, OneToOneField, and ManyToManyField become proper cardinality arrows.

🔎 Hover for relations

Hover over ForeignKey('app.Model') in any Python file → a card pops up with the target model's fields, relations, and a "Jump to" link. No Ctrl+F, no file dialog.

🧭 Jump-to-definition

Click any field in the tree → cursor lands on the exact line. Filter the tree by app or model name. Split models/ packages are fully supported.

⚡ Zero configuration

No DJANGO_SETTINGS_MODULE. No runserver. Parses models.py statically. Works with a broken venv, a missing dependency, or on someone else's laptop.

🎨 Native VS Code UI

Dark theme. Light theme. Your theme. Follows your icon theme, your font, your key bindings. Nothing garish, nothing branded.

🚀 v0.8 — five new "wow" features

🎯 Inline QuickFixes (16 rules)

Static analysis over .py files with Ruff-style codes (DOL001..DOL032), Clippy-style Applicability, and per-rule severity overrides. .count() > 0.exists(), null=True on CharField, missing on_delete, datetime.now()timezone.now() and a dozen more.

Suppress inline with # django-orm-lens-disable-next-line DOL007.

🧪 Factory generator

Right-click any model → factory_boy DjangoModelFactory scaffold with Faker providers keyed by field type. CharField(max_length) scales word-count buckets, DecimalField(N,D) computes left_digits=N-D, choices= maps to Iterator, M2M gets @post_generation. FK chains pull related factories transitively.

Also available as CodeLens above each model class.

🕰 Time-Travel Schema Diff

Pick a models.py, pick two commits, get a typed diff as PR-ready markdown. AddModel / DropModel / RenameModel / ModifyModel events with confidence-scored rename detection (Levenshtein + field-shape Jaccard).

Renames are first-class events, never Add + Drop. Blob-SHA LRU cache — commits that don't touch models.py share their parsed snapshot.

🔎 Impact analysis

"What breaks if I remove this field?" — right-click a field or model → workspace-wide scan grouped by Django layer (models, serializers, forms, admin, views, urls, templates, tests, migrations).

Findings carry a Certain / Likely / Possibly confidence tag. Handles ORM string refs (order_by("-author")), kwarg lookups (filter(author__id=1)), Meta.fields tuples, and template variables.

⚡ Interactive query builder

Right-click a field or model → pick a template → snippet inserted at cursor (with tab-stops) or in a fresh untitled buffer.

.filter(field=?) on an FK auto-appends .select_related(...), .annotate(post_count=Count('post_set')) honours related_name, .prefetch_related for M2M, .values('field').distinct(), .only('field').

🎨 Sidebar UX overhaul

Stable TreeItem.id — refresh no longer collapses the tree. Rich MarkdownString tooltips with command: deep-links. Activity-bar badge counts DOL### issues.

FileDecorationProvider badges: red ! on FK-without-on_delete, yellow ~ on null=True string fields (bubbles up to the parent Model row, Git-style).

📸 What it looks like

Also included in the extension:

  • 🕸️ Live ER diagram — Mermaid cardinality arrows, edge labels (CASCADE, through Model, as related_name), theme-aware, one-click SVG export
  • 🔎 Hover cards — over any ForeignKey('app.Model') or ManyToManyField(...), with a one-click jump link
  • 🧭 CodeLens — above every class Model line: field count, relation count, and an Open ER diagram action
  • 🎨 Named themesauto / default / dark / forest / neutral for the diagram webview

🤖 For terminals and AI coding agents

The same parser that powers the VS Code extension ships as a standalone Python package — with an optional MCP (Model Context Protocol) server so any MCP-compatible AI agent can navigate your Django schema without importing Django or booting your app.

CLI

django-orm-lens scan -f json                # every app, every model, every field
django-orm-lens describe blog.Post          # one model in Markdown
django-orm-lens hover blog.Post             # compact hover card
django-orm-lens list | fzf                  # flat app.Model — pipes anywhere
django-orm-lens er > schema.mmd             # Mermaid ER diagram
django-orm-lens diff before.json after.json # what a PR changes structurally
django-orm-lens nplusone --path .           # static N+1 detector (v0.6+)
django-orm-lens migration-risk --path .     # flag risky migration ops (v0.6+)

Every command accepts --path <dir> and --exclude <glob>. nplusone / migration-risk / diff exit code 1 on findings — drop them into CI to block PRs on regressions.

MCP server

Register it once with your agent and it exposes five read-only tools:

Tool Purpose
list_apps Every Django app in the workspace with model counts
list_models Flat app.Model list, optional app filter
describe_model Full field / relation / Meta detail for one model
find_relations Inbound + outbound relations for one model
er_diagram Mermaid erDiagram for the whole workspace
# Start it directly
django-orm-lens-mcp

# Or via the CLI subcommand
django-orm-lens mcp

Workspace resolution (py-1.3.0+). Every tool accepts an optional workspace_root argument on the call. Resolution priority: explicit arg → $DJANGO_ORM_LENS_ROOT → current working directory. Invalid or non-Django paths return a structured envelope ({"error": "WORKSPACE_NOT_DJANGO", "hint": "…"}) instead of empty results, so the agent can self-correct. Optional sandbox via DJANGO_ORM_LENS_ALLOWED_ROOTS (;-separated on Windows, : elsewhere).

🔌 Integrations

Client How to enable Status
VS Code code --install-extension frowningdev.django-orm-lens
Cursor same VSIX + optional MCP entry in ~/.cursor/mcp.json
Windsurf / VSCodium / any Code fork install the VSIX from the Marketplace or GitHub Releases
Aider add django-orm-lens-mcp to your mcp.json ✅ (via MCP)
Continue.dev register the MCP server in ~/.continue/config.json ✅ (via MCP)
Zed register the MCP server in Zed settings ✅ (via MCP)
Any MCP-compatible client point command at django-orm-lens-mcp, set DJANGO_ORM_LENS_ROOT
Discoverable via MCP Registry official Model Context Protocol server directory
Plain terminal / CI pip install django-orm-lens && django-orm-lens scan

Example: Cursor / any MCP client

{
  "mcpServers": {
    "django-orm-lens": {
      "command": "django-orm-lens-mcp",
      "env": { "DJANGO_ORM_LENS_ROOT": "/abs/path/to/your/project" }
    }
  }
}

🚀 Get started (30 seconds)

In VS Code:

  1. code --install-extension frowningdev.django-orm-lens
  2. Open a folder with a manage.py or models.py
  3. Click the Django ORM Lens icon in the activity bar
  4. Expand apps → models → fields
  5. Click the type-hierarchy icon at the top of the panel → ER diagram opens beside your code

In a terminal:

pip install django-orm-lens
cd my-django-project
django-orm-lens scan -f table

As an AI agent tool:

pip install "django-orm-lens[mcp]"

…then register django-orm-lens-mcp in your agent's MCP config (see the Integrations table above).

No settings screen. No sign-in. No telemetry.

🎯 Who this is for

  • Django developers joining a codebase with 10+ apps and getting lost in models.py sprawl.
  • Contract / freelance engineers who need to grasp an unfamiliar Django project in the first hour, not the first week.
  • Teams onboarding new hires who want a one-glance schema view without spinning up documentation infrastructure.
  • AI-agent power users (Cursor / Aider / Zed / Continue / any MCP-compatible client) who need the agent to answer schema questions accurately — without giving it database credentials or booting Django.
  • CI pipelines that verify schema shape (e.g. "did we accidentally break a related_name?") without importing the project.
  • Solo indie devs on a broken venv or someone else's laptop — no runserver, no manage.py migrate, still works.

🗺️ Market position

Django ORM Lens sits at the intersection of editor tooling and AI-agent tooling — a slot no existing package covers:

Segment Existing option What it costs you
Boot-and-graph django-extensions graph_models Requires Graphviz + Django settings + a working DB URL
Web-based viewer django-schema-graph Requires a running Django server; hosts one more thing to break
Admin panel Django Admin Requires runserver + auth + database — great for data, not for architecture
Editor plugin PyCharm's Django Structure Locked to PyCharm; no CLI, no AI-agent story
MCP server (none until now) AI agents guess your schema from source, imperfectly

Django ORM Lens is the only tool that ships three surfaces from one parser: a VS Code extension (any Code fork), a zero-dep CLI (terminals + CI), and an MCP server (AI agents). All static. All free. All MIT.

🤔 How is this different?

Django ORM Lens django-extensions graph_models django-schema-graph Django Admin PyCharm Django Structure
Works without a bootable Django project ⚠️
Zero-install (no graphviz, no server) ❌ (needs PyCharm)
Works in VS Code / Cursor / any Code fork
Sidebar tree inside the editor
Live ER diagram
Hover cards on ForeignKey ⚠️
CodeLens on model classes
Split models/ package support ⚠️ ⚠️
CLI for terminal / CI ⚠️
MCP server for AI agents
Discoverable in the MCP Registry
Free & open-source (MIT) ❌ (paid IDE)
Django version support 4.0 – 5.2 latest 3.2 – 4.1 (stale since 2023) latest latest

django-schema-graph has not been updated since 2023-05 and does not test Django 5.x.

⚙️ Configuration

The defaults are opinionated and sensible. If you need to tweak:

// .vscode/settings.json
{
  "djangoOrmLens.excludeGlobs": [
    "**/migrations/**",
    "**/node_modules/**",
    "**/venv/**",
    "**/.venv/**",
    "**/env/**"
  ],
  "djangoOrmLens.autoRefresh": true
}
Setting Type Default What it does
djangoOrmLens.excludeGlobs string[] See above Glob patterns to skip when scanning
djangoOrmLens.autoRefresh boolean true Rescan on models.py changes
djangoOrmLens.codeFixes.enabled boolean true Master switch for the DOL### diagnostics + QuickFixes
djangoOrmLens.rules object {} Per-rule severity: { "DOL007": "off", "DOL013": "error" }
djangoOrmLens.rulesSelect string[] [] Ruff-style select. ["DOL0"] runs only queryset+model rules
djangoOrmLens.rulesIgnore string[] [] Ruff-style ignore. ["DOL03"] silences form/view rules

🔬 Rule catalogue (v0.8)

Sixteen static-analysis checks over .py files. All are line-oriented (no Python process required), grouped into four categories, and individually toggle-able. Every rule has a stable DOL### code that appears in the Problems panel and links to its docs.

Queryset

Code Rule Default Applicability
DOL001 .count() > 0.exists() info safe
DOL002 .count() == 0not .exists() info safe
DOL003 .first() is Nonenot .exists() info safe
DOL004 .first() is not None.exists() info safe
DOL005 .filter().exclude()Q(...) & ~Q(...) hint suggestion
DOL006 for x in list(qs):for x in qs: info safe
DOL007 FK attribute access inside for-loop (N+1) warning unsafe

Model definition

Code Rule Default Applicability
DOL011 CharField / TextField(null=True)blank=True warning suggestion
DOL012 Model without __str__ method info suggestion
DOL013 ForeignKey without on_delete error suggestion
DOL014 CharField without max_length error suggestion
DOL015 TextField(max_length=...) has no DB effect hint suggestion

Datetime

Code Rule Default Applicability
DOL021 datetime.now()timezone.now() warning suggestion
DOL022 datetime.utcnow() (deprecated 3.12) warning suggestion

Forms / views

Code Rule Default Applicability
DOL031 render(request, tpl, locals()) — explicit dict warning suggestion
DOL032 Meta.fields = '__all__' — audit surface warning unsafe

Suppress inline

# django-orm-lens-disable-next-line DOL007
for user in User.objects.all():
    print(user.profile)  # not flagged

qs.count() > 0  # django-orm-lens-disable-line DOL001

# django-orm-lens-disable DOL011  ← on its own line, kills DOL011 for the rest of the file

Applicability follows Rust's Clippy: safe fixes can be applied automatically ("Fix All"), suggestion fixes are offered as a QuickFix but reviewed, unsafe findings never auto-apply. Fixes are separated from analyzers (Roslyn-style), so one rule can grow multiple fixers over time without touching detection logic.

🧭 Commands

Open the command palette (Ctrl+Shift+P / Cmd+Shift+P) and type "Django ORM Lens":

Command What it does
Django ORM Lens: Refresh Force-rescan the workspace
Django ORM Lens: Show ER Diagram Open the Mermaid ER diagram side-by-side
Django ORM Lens: Filter Models Filter the tree by app / model / field name
Django ORM Lens: Clear Filter Restore the full tree
Django ORM Lens: Jump to Model Programmatic — triggered by tree clicks and hover cards
Django ORM Lens: Find Reverse References Right-click a model — QuickPick of every FK pointing at it
Django ORM Lens: Generate factory_boy Factory Right-click a model or use CodeLens — scaffold a DjangoModelFactory
Django ORM Lens: Schema Diff (Time-Travel) Pick two commits — get a typed diff as a markdown buffer
Django ORM Lens: Find Impact (What Uses This?) Right-click a field or model — workspace-wide reference scan
Django ORM Lens: Build Query (Insert Snippet) Right-click a field or model — pick an ORM template

🗺️ Roadmap

Shipped

  • Sidebar tree grouped by app
  • Live Mermaid ER diagram
  • Hover cards over ForeignKey('app.Model')
  • Filter tree by name
  • Split models/ package support
  • Export ER diagram as SVG
  • Python CLI + MCP server for terminals and AI agents
  • Welcome view for empty workspaces
  • Path-safe jump-to-definition and sanitized hover markdown
  • v0.3.0 — CodeLens above each model class (N fields · N relations · Open ER diagram)
  • v0.3.0 — Edge labels on the diagram (CASCADE, SET_NULL, PROTECT, related_name)
  • v0.3.0 — Named color themes (auto / default / dark / forest / neutral)
  • v0.3.1through_model on M2M edges (contributed by @kingrubic)
  • v0.3.1 — Listed in the official MCP Registry + Glama.ai
  • v0.6.0 — CLI nplusone — static N+1 detector (FK/M2M access inside loops without select_related/prefetch_related)
  • v0.6.0 — CLI migration-risk — flags 7 classes of production hazards in migrations/*.py
  • v0.6.0 — CLI diff — compare two schema JSON dumps for PR review
  • v0.6.0 — ER-diagram minimap color-codes nodes by Django app
  • v0.6.0 — README translations: 🇷🇺 Russian, 🇪🇸 Spanish, 🇨🇳 Chinese
  • v0.6.0 — Docker image on GHCR: docker run ghcr.io/frowningdev/django-orm-lens
  • v0.7.0settings.AUTH_USER_MODEL resolves everywhere: n+1 reverse-relations, signal senders, Mermaid ER, VS Code webview, inbound-relation panel, React ER
  • v0.7.0 — AST-based field parser: ForeignKey(on_delete=CASCADE, to='User') resolves regardless of kwarg order (Python + TS parity)
  • v0.7.0 — Public shared helpers: find_user_model, resolve_related_tail, find_model, iter_workspace_py_files (Python) + findUserModel, resolveRelatedTail (TS)
  • v0.7.0--verbose no longer walks the tree twice; WorkspaceIndex.scanned_files carries the count
  • v0.7.3 — PEP-526 type annotations on fields (jti: CharField[str] = models.CharField(...)) now parse — reported by @jsabater (#25) with a clean Django Ninja 1.6 repro
  • v0.7.4 — PEP-695 generic class headers (Python 3.12+): class Container[T](https://github.com/FROWNINGdev/django-orm-lens/blob/main/models.Model): now parses
  • v0.7.5 — Aliased models module (from django.db import models as m) and third-party field packages (jsonfield.JSONField) now detected
  • v0.7.6 — Tab-indented model bodies now parse (editors defaulting to tabs no longer show empty models)
  • v0.8.0 — Inline QuickFixes: 16 rules (DOL001..DOL032) with per-rule severity + Ruff-style select/ignore + inline # django-orm-lens-disable-next-line
  • v0.8.0 — Factory generator: factory_boy scaffold from any model with Faker providers keyed by field type
  • v0.8.0 — Time-Travel Schema Diff: pick two commits → typed markdown diff with first-class rename detection
  • v0.8.0 — Impact analysis: workspace-wide field-reference scan across every Django layer with Certain/Likely/Possibly confidence tags
  • v0.8.0 — Interactive Query Builder: right-click → template → snippet inserted at cursor, grammar-aware (FK gets .select_related, related_name honoured)
  • v0.8.0 — Sidebar UX overhaul: stable TreeItem.id, MarkdownString tooltips with command: deep-links, FileDecorationProvider badges, TreeView.badge on the activity bar, three when-gated viewsWelcome states

Next

  • ORM query autocomplete inside .filter() / .exclude() / .annotate() (#3)
  • App / model toggle checkboxes to declutter huge schemas
  • Migration dependency graph
  • pre-commit hook wrapping migration-risk + nplusone

Later

  • Third-party field support (django-mptt, django-taggit, django-model-utils)
  • JetBrains / PyCharm plugin (if there is demand)

Vote by 👍-ing the corresponding issue.

❓ FAQ

🆘 Support

📜 License

MIT © FROWNINGdev

Made for developers who care about their codebase.

Marketplace · PyPI · GitHub · Issues · Discussions · Sponsor