Django 및 SQLAlchemy 모델에 대한 정적 분석을 수행하여 데이터베이스 없이도 N+1 쿼리, 마이그레이션 위험 및 스키마 관계를 탐지합니다.
다른 이름 FROWNINGdev/django-orm-lens, django-orm-lens
- 스타
- 106
- Tools
- —
- 다운로드, 30일
- 699
- 최신 버전
- 1.15.0
- 마지막 커밋
- 2026년 11월 11일
- 라이선스
- MIT
ORM Lens MCP란?
ORM Lens은(는) MCP server입니다. Django 및 SQLAlchemy 모델에 대한 정적 분석을 수행하여 데이터베이스 없이도 N+1 쿼리, 마이그레이션 위험 및 스키마 관계를 탐지합니다.
프로젝트 README에서 생성된 요약
ORM Lens MCP server 정보
Django ORM Lens는 실행 중인 데이터베이스, 작동하는 가상 환경 또는 settings 모듈 없이도 Django 및 SQLAlchemy 모델에 대한 정적 분석을 제공합니다. 모델과 마이그레이션을 직접 파싱하여 인사이트를 생성하므로 로컬 개발, CI 파이프라인 또는 AI agent를 통한 사용에 적합합니다. 개발자는 이를 통해 ER 다이어그램으로 스키마 관계를 시각화하고 잠재적인 성능 병목 현상을 탐지할 수 있습니다.
이 도구는 N+1 쿼리 탐지, 마이그레이션 위험 평가, 스키마 드리프트 탐지 등 여러 특화된 기능을 제공합니다. AI 기반 워크플로우의 경우, MCP server는 14개의 읽기 전용 도구를 제공하여 agent가 실제 데이터를 바탕으로 스키마 관련 질문에 답변할 수 있게 합니다. 사용자는 VS Code 또는 Cursor와 같은 에디터에 통합하거나, uvx 또는 pip를 사용하여 CLI에서 실행하거나, Docker 컨테이너를 사용하여 배포할 수 있습니다. ORM_LENS_ROOT를 프로젝트 경로로 지정하면 클론 직후의 상태나 환경이 깨진 상태에서도 작동하도록 설계되었습니다.
활용 사례
- 1N+1 쿼리 루프 탐지비효율적인 데이터베이스 액세스 패턴을 식별하고 이를 해결하기 위해 필요한 select_related 또는 selectinload 호출을 찾아냅니다.
- 2마이그레이션 위험 평가Django 마이그레이션과 Alembic 리비전을 분석하여 테이블 잠금이나 오류를 유발할 수 있는 작업을 찾아냅니다.
- 3AI agent를 통한 스키마 쿼리AI agent가 정적 분석을 사용하여 데이터베이스 스키마에 관한 구체적인 질문에 답변할 수 있는 기능을 제공합니다.
- 4마이그레이션 영향 평가파괴적인 마이그레이션의 영향 범위나 특정 필드 삭제가 계층 간에 미치는 영향을 결정합니다.
프로젝트의 README를 바탕으로 작성되었습니다. 모든 활용 사례는 해당 내용의 인용문과 대조하여 확인합니다.
ORM Lens MCP 설치 방법
형식 확인: 2026년 11월 10일Cursor에 추가Goose에 추가Claude Code에 ORM Lens MCP 설치
$ claude mcp add django-orm-lens -- uvx django-orm-lensCursor에 ORM Lens MCP 설치
~/.cursor/mcp.json
{
"mcpServers": {
"django-orm-lens": {
"command": "uvx",
"args": [
"django-orm-lens"
]
}
}
}VS Code에 ORM Lens MCP 설치
.vscode/mcp.json
{
"servers": {
"django-orm-lens": {
"type": "stdio",
"command": "uvx",
"args": [
"django-orm-lens"
]
}
}
}VS Code CLI에 ORM Lens MCP 설치
$ code --add-mcp '{"name":"django-orm-lens","type":"stdio","command":"uvx","args":["django-orm-lens"]}'Claude Desktop에 ORM Lens MCP 설치
claude_desktop_config.json
{
"mcpServers": {
"django-orm-lens": {
"command": "uvx",
"args": [
"django-orm-lens"
]
}
}
}Codex에 ORM Lens MCP 설치
$ codex mcp add django-orm-lens -- uvx django-orm-lensCodex config.toml에 ORM Lens MCP 설치
~/.codex/config.toml
[mcp_servers.django-orm-lens] command = "uvx" args = ["django-orm-lens"]
Gemini CLI에 ORM Lens MCP 설치
$ gemini mcp add -s user django-orm-lens uvx -- django-orm-lensGemini settings.json에 ORM Lens MCP 설치
~/.gemini/settings.json
{
"mcpServers": {
"django-orm-lens": {
"command": "uvx",
"args": [
"django-orm-lens"
]
}
}
}구성
ORM_LENS_ROOT
| 이름 | 설명 | 유형 |
|---|---|---|
| ORM_LENS_ROOT | — |
자동 검사
2026년 11월 12일에 실행됨전체 보고서 →자동 검사를 통과했습니다. 이는 보안 감사가 아닙니다. 코드를 직접 읽고 서버에 필요한 최소한의 권한만 부여하십시오. 검사 방식
- 소스 저장소 연결 및 접근 가능통과
- 오픈 소스 라이선스 (OSI)통과
- 최근 1년 내 커밋 또는 릴리스통과
- 패키지 이름이 인기 패키지와 유사하지 않음통과
- 원격 엔드포인트가 HTTPS 사용검사되지 않음
- 파괴적인 도구에 라벨 표시됨검사되지 않음
- 모델에 대한 숨겨진 지침 없음통과
- 패키지 및 해당 종속성에 중요한 보안 권고 없음통과
README
GitHub에서 보기English · Русский · Español · 中文
ORM Lens
ER diagrams, N+1 detection and migration-risk checks for Django and SQLAlchemy — without booting either.
Your entire model graph — live in your editor sidebar, gating your CI, and answering your AI agent over MCP. All from static parsing: no database, no runserver, no working venv. Django models and migrations, SQLAlchemy models and Alembic revisions.
Formerly django-orm-lens. pip install django-orm-lens still works and installs orm-lens.
Replaces: graph_models + django-schema-graph + hand-drawn ER diagrams + grep archaeology.
Featured in Django News #347 · PyCoder's Weekly #746
⚡ 10 seconds to first insight
uvx orm-lens scan -f table # every app and model at a glance
uvx orm-lens nplusone # N+1 loops, with the select_related / selectinload to add
uvx orm-lens migration-risk # Django migrations and Alembic revisions that lock tables or fail
Cold clone, broken venv, no settings module — you still see every app and model of the project, then the N+1 loops and risky migrations in it, right in your terminal. (uvx is from uv; pipx run works the same way.)
Then pick your surface — three distributions, one parser core:
| You are | Install | You get |
|---|---|---|
| Editor user (Django) — VS Code / Cursor / Windsurf / VSCodium | code --install-extension frowningdev.django-orm-lens |
Field autocomplete in .filter(), sidebar tree, live ER diagram, hover cards, 18 lint rules with QuickFixes |
| Terminal / CI user | pip install orm-lens |
17 subcommands, SARIF + PR annotations, pre-commit hooks, a GitHub Action |
| AI-agent user — Cursor / Claude Code / Aider / Zed / Continue | pip install "orm-lens[mcp]" |
14 read-only MCP tools answering schema questions from ground truth |
MCP setup is one JSON block — see Integrations. Point ORM_LENS_ROOT at your project's absolute path.
🆓 Paid-tier capabilities, free and MIT
Schema review is a paid category nearly everywhere. A bot that reviews every pull request, analysis that follows a queryset past the function it was built in, a check that catches schema drift, index advice grounded in real table statistics — those normally sit behind a per-seat or per-database subscription.
All of it is here, MIT-licensed, with no tier gate, no seat count, no account, and no telemetry:
| Capability usually sold as a paid tier | Here |
|---|---|
| PR review bot for schema changes — posts once, then updates in place | blast-radius + the Action |
| Analysis that follows a queryset across functions | nplusone |
| Schema drift detection | drift |
| Index proposals from observed QuerySet usage | suggest-indexes |
| Migration risk weighed against real table sizes | blast-radius --stats |
| Blast radius of a destructive migration | blast-radius |
| Cross-layer impact of removing a field | impact |
There is no Pro tier, and none is planned. If the tool saves you an afternoon, a star is the entire ask.
📊 Traction
If the tool saves you a
grepnext 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 ORM Lens in the Extensions view — same publisher frowningdev on both registries.
Terminal & AI coding agents:
pip install orm-lens # CLI only
pip install "orm-lens[mcp]" # + MCP server for AI agents
Requires Python 3.9+ (the MCP server: 3.10+). Zero runtime dependencies for the CLI.
Docker (v0.6+):
docker run --rm -v "$PWD:/workspace" ghcr.io/frowningdev/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
Ordermodel, and how is it connected toUser?"
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 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.
🚀 Power features
💥 Blast radius
The review-time question a schema change actually raises: what does this hit? Every destructive migration operation becomes a target carrying its risks, every place in the codebase that still reads it, and — for whole-model operations — the cascade fallout.
migration-risk, impact and cascade each answer a third of that; nobody joins them by hand, so the tool does. --format markdown is a postable PR comment; --stats turns "probably populated" into ~41 000 000 rows, 12.0 GB from a read-only query you run yourself, with no database credential anywhere near CI.
🧭 Schema drift
makemigrations --check without booting Django. Each app's migrations are replayed in order into the field set they imply, then compared against what models.py declares.
Django's own check needs a working settings module, an importable app registry and every dependency installed — unavailable on a cold clone or a broken venv, which is exactly when the answer is cheapest to act on. Only the dangerous direction fails the build: a field declared but never migrated means the column will not exist, and the first query touching it errors.
🎯 Inline diagnostics & QuickFixes (18 rules)
Static analysis over .py files with Ruff-style codes (DOL001..DOL041), Clippy-style Applicability, and per-rule severity overrides. .count() > 0 → .exists(), null=True on CharField, missing on_delete, datetime.now() → timezone.now(), planner-GUC overrides in raw SQL (enable_*, plan_cache_mode, jit*; diagnostic-only), and a dozen more.
Suppress inline with # 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
Live sample — real orm-lens er output, rendered by GitHub right here:
erDiagram
User {
CharField display_name
}
Tag {
CharField name
}
Post {
CharField title
DateTimeField created_at
}
Comment {
TextField body
}
Post }o--|| User : "author [CASCADE, as posts]"
Post }o--o{ Tag : "tags [as posts]"
Comment }o--|| Post : "post [CASCADE, as comments]"
Comment }o--|| User : "author [SET_NULL]"
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')orManyToManyField(...), with a one-click jump link - 🧭 CodeLens — above every
class Modelline: field count, relation count, and an Open ER diagram action - 🎨 Named themes —
auto/default/dark/forest/neutralfor the diagram webview
🧪 SQLAlchemy, FastAPI and Flask (preview)
The CLI and the MCP server read SQLAlchemy projects the same way they read Django ones: parsed with ast, never imported, no database.
uvx orm-lens scan -f table # SQLAlchemy 2.0 / 1.x, Flask-SQLAlchemy and SQLModel models
uvx orm-lens er -f mermaid # ER diagram from the foreign keys and many-to-many tables
uvx orm-lens nplusone # lazy relationship() reads in loops, with the selectinload to add
uvx orm-lens migration-risk # Alembic revisions: NOT NULL without server_default, locking indexes, multiple heads
app/views.py:12 [high] loop=user qs=users
accessed: addresses
fix: .options(selectinload(User.addresses))
Tuned against Superset, Airflow, Prefect, Polar, Dispatch, Mealie, CTFd, Redash and the FastAPI template: 517 models read, and every N+1 finding on them checked by hand and real. Details: SQLAlchemy models · Alembic rules. The VS Code extension is Django-only for now.
🤖 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
orm-lens scan -f json # every app, every model, every field
orm-lens describe blog.Post # one model in Markdown
orm-lens list | fzf # flat app.Model — pipes anywhere
orm-lens er > schema.mmd # ER diagram — Mermaid (default)
orm-lens er -f dbml > schema.dbml # …or DBML: paste into dbdiagram.io
orm-lens er -f d2 > schema.d2 # …or D2 / plantuml / dot
orm-lens diff before.json after.json # what a PR changes structurally
orm-lens nplusone --format github # N+1 findings as PR annotations
orm-lens migration-risk -f sarif # SARIF for GitHub Code Scanning
orm-lens migration-risk --path api/ # Alembic revisions too (FastAPI, Flask)
orm-lens suggest-indexes blog.Post # Meta.indexes proposals from usage
orm-lens signals # sender→signal→handler graph
orm-lens migration-deps blog -f mermaid # per-app migration DAG
orm-lens cascade blog.Author # what one delete() takes down
orm-lens impact author # what still references a field
orm-lens blast-radius -f markdown # risks + who still reads them
orm-lens drift # migrations vs models, no boot
orm-lens stats-sql # read-only SQL for --stats
impact,blast-radius,driftandstats-sqlship in py-1.7.0 and later.
Alembic (preview):
migration-riskalso checks Alembic revisions — NOT NULL withoutserver_default, indexes withoutCONCURRENTLY, multiple heads and nine more rules — so SQLAlchemy projects without Django (FastAPI, Flask) get the same static migration review.
Django 6.1:
on_delete=models.DB_CASCADEdeletes child rows in the database, so theirpost_deletehandlers never run. Since py-1.13.8,cascadenames the handlers eachDB_CASCADErelation skips — why that matters and what to do.
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 fourteen 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 |
cascade_preview |
Blast radius of one delete(), grouped by on_delete, plus the post_delete receivers Django 6.1's DB_CASCADE skips |
er_diagram |
ER diagram — mermaid / dbml / d2 / plantuml / dot |
describe_migration_dependency |
Per-app migration DAG: roots, leaves, cross-app deps |
suggest_indexes |
Meta.indexes proposals from observed QuerySet usage |
signal_graph |
Sender→signal→handler graph from @receiver decorators and signal.connect() calls |
migration_risk |
Dangerous schema changes in Django migrations & Alembic revisions (table locks, dropped columns) |
blast_radius |
What a destructive migration hits: its risks, the code still reading it, the cascade fallout |
drift |
makemigrations --check without booting Django — migrations diffed against models.py |
impact |
Every reference to a field or model name, grouped by Django layer |
nplusone_scan |
Static N+1 findings for the whole workspace |
# Start it directly
orm-lens-mcp
ORM Lens MCP 질문
ORM Lens MCP를 Claude Code에 추가하려면 어떻게 하나요?
터미널에서 claude mcp add django-orm-lens -- uvx django-orm-lens를 실행합니다. 모든 프로젝트에서 사용할 수 있게 하려면 --scope user를 추가합니다.
ORM Lens MCP를 Cursor에 추가하려면 어떻게 하나요?
~/.cursor/mcp.json를 열고 mcpServers 아래에 서버를 추가합니다. 위 설치 섹션에 표시된 Cursor 구성을 사용합니다.
실행 중인 데이터베이스나 환경이 필요한가요?
아니요, 정적 파싱을 사용하므로 데이터베이스, 실행 중인 서버 또는 작동하는 가상 환경 없이도 작동합니다.
MCP server가 AI agent를 위해 무엇을 할 수 있나요?
MCP server는 14개의 읽기 전용 도구를 제공하여 AI agent가 실제 데이터를 바탕으로 데이터베이스 스키마에 관한 질문에 답변할 수 있도록 합니다.
지원되는 ORM은 무엇인가요?
Django 모델과 SQLAlchemy 모델을 모두 지원합니다.