Django ORM Lens

Análise estática de esquema Django para agentes de IA — 10 ferramentas somente leitura (models, relações, diagramas ER, DAG de migrações, varredura N+1) sem banco de dados e sem inicialização do Django.

Documentação

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

Django ORM Lens — live sidebar and ER diagram for your Django models

Django ORM Lens

Diagramas ER, detecção de N+1 e verificações de risco de migração para Django — sem inicializá-lo.

Todo o seu grafo de modelos — ao vivo na barra lateral do editor, controlando seu CI e respondendo ao seu agente de IA via MCP. Tudo a partir de análise estática: sem banco de dados, sem runserver, sem venv funcional.

Substitui: graph_models + django-schema-graph + diagramas ER desenhados à mão + arqueologia de grep.


PyPI Python Django versions CI Downloads License


Install on VS Code Install on Open VSX Docker GHCR


Destaque em Django News #347 · PyCoder's Weekly #746


⚡ 10 segundos para o primeiro insight

uvx django-orm-lens scan -f table   # every app and model at a glance
uvx django-orm-lens nplusone        # N+1 loops, with the select_related to add
uvx django-orm-lens migration-risk  # migrations that lock tables or fail on existing rows

Clone frio, venv quebrado, sem módulo de settings — você ainda vê todos os apps e modelos do projeto, depois os loops N+1 e migrações arriscadas, direto no seu terminal. (uvx é do uv; pipx run funciona da mesma forma.)

Depois escolha sua superfície — três distribuições, um núcleo de parser:

Você éInstalaçãoVocê recebe
Usuário de editor — VS Code / Cursor / Windsurf / VSCodiumcode --install-extension frowningdev.django-orm-lensAutocompletar de campos no .filter(), árvore na barra lateral, diagrama ER ao vivo, cards de hover, 18 regras de lint com QuickFixes
Usuário de terminal / CIpip install django-orm-lens17 subcomandos, SARIF + anotações de PR, hooks de pre-commit, uma GitHub Action
Usuário de agente de IA — Cursor / Claude Code / Aider / Zed / Continuepip install "django-orm-lens[mcp]"13 ferramentas MCP somente leitura respondendo perguntas de schema a partir da fonte da verdade

A configuração do MCP é um bloco JSON — veja Integrações. Aponte DJANGO_ORM_LENS_ROOT para o caminho absoluto do seu projeto Django.


🆓 Recursos de nível pago, gratuitos e MIT

Revisão de schema é uma categoria paga em quase todo lugar. Um bot que revisa cada pull request, análise que segue um queryset além da função onde foi criado, uma verificação que detecta drift de schema, conselhos de índice baseados em estatísticas reais de tabela — tudo isso normalmente fica atrás de uma assinatura por usuário ou por banco de dados.

Tudo isso está aqui, licenciado sob MIT, sem limite de tier, sem contagem de assentos, sem conta e sem telemetria:

Recurso normalmente vendido como tier pagoAqui
Bot de revisão de PR para mudanças de schema — posta uma vez, depois atualiza no lugarblast-radius + a Action
Análise que segue um queryset entre funçõesnplusone
Detecção de drift de schemadrift
Propostas de índice a partir do uso observado de QuerySetsuggest-indexes
Risco de migração ponderado contra tamanhos reais de tabelablast-radius --stats
Raio de impacto de uma migração destrutivablast-radius
Impacto entre camadas da remoção de um campoimpact

Não existe tier Pro, e nenhum está planejado. Se a ferramenta economizar uma tarde para você, uma estrela é todo o pedido.


📊 Tração

GitHub stars Forks Contributors PyPI monthly Total downloads Open VSX downloads VS Code installs Marketplace rating Last commit


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

Se a ferramenta economizar um grep na próxima vez que você mexer em um projeto Django estranho — uma estrela ajuda outros a encontrá-la.

📈 Crescimento de estrelas


⚡ Instalação

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

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

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

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

Ou pesquise Django ORM Lens na visualização de Extensões — mesmo publisher frowningdev em ambos os registros.

Agentes de terminal e codificação com IA:

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

Requer Python 3.9+. Zero dependências de runtime para a CLI.

Docker (v0.6+):

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

Multi-arquitetura (amd64 + arm64). Sem Python necessário no host. Bom para CI e auditorias pontuais.


🎯 O problema

Funciona offline. Funciona em um venv quebrado. Funciona no laptop de outra pessoa. Funciona no CI.

Você abre um projeto Django. Ele tem 20 apps. Você precisa responder a uma pergunta simples:

"Qual app é dono do modelo Order, e como ele está conectado ao User?"

Hoje, isso significa: Ctrl+P, "models", rolar por 30 resultados, abrir cinco arquivos, Ctrl+F por class Order, ler 400 linhas de strings ForeignKey('otherapp.Something'), tentar lembrar o que você aprendeu dois arquivos atrás.

Meio dia perdido. Toda vez. Em todo projeto.


✨ Com Django ORM Lens

📚 Uma árvore de tudo

Cada app → cada modelo → cada campo → cada opção Meta. Agrupado por aplicação, ordenado alfabeticamente, expansível.

Ícones distinguem CharField de ForeignKey de ManyToManyField de relance.

🕸️ Um diagrama ER ao vivo

Um comando abre um diagrama de entidade-relacionamento Mermaid de todo o seu schema. Veja-o redesenhar enquanto você edita. Exporte para SVG.

ForeignKey, OneToOneField e ManyToManyField se tornam setas de cardinalidade adequadas.

🔎 Hover para relações

Passe o mouse sobre ForeignKey('app.Model') em qualquer arquivo Python → um card aparece com os campos do modelo alvo, relações e um link "Ir para". Sem Ctrl+F, sem diálogo de arquivo.

🧭 Ir para definição

Clique em qualquer campo na árvore → o cursor pousa na linha exata. Filtre a árvore por nome de app ou modelo. Pacotes models/ divididos são totalmente suportados.

⚡ Zero configuração

Sem DJANGO_SETTINGS_MODULE. Sem runserver. Analisa models.py estaticamente. Funciona com venv quebrado, dependência ausente ou no laptop de outra pessoa.

🎨 UI nativa do VS Code

Tema escuro. Tema claro. Seu tema. Segue seu tema de ícones, sua fonte, seus atalhos de teclado. Nada chamativo, nada com marca.


🚀 Recursos avançados

💥 Raio de impacto

A pergunta no momento da revisão que uma mudança de schema realmente levanta: o que isso atinge? Cada operação de migração destrutiva se torna um alvo carregando seus riscos, cada lugar no código que ainda a lê e — para operações de modelo inteiro — o efeito cascata.

migration-risk, impact e cascade respondem cada um a um terço disso; ninguém os junta manualmente, então a ferramenta faz isso. --format markdown é um comentário de PR postável; --stats transforma "provavelmente populado" em ~41 000 000 rows, 12.0 GB a partir de uma consulta somente leitura que você mesmo executa, sem credencial de banco de dados perto do CI.

🧭 Drift de schema

makemigrations --check sem inicializar o Django. As migrações de cada app são reproduzidas em ordem no conjunto de campos que implicam e depois comparadas com o que models.py declara.

A própria verificação do Django precisa de um módulo de settings funcional, um registro de apps importável e todas as dependências instaladas — indisponível em um clone frio ou venv quebrado, que é exatamente quando a resposta é mais barata de agir. Apenas a direção perigosa falha o build: um campo declarado mas nunca migrado significa que a coluna não existirá, e a primeira consulta que o toca gera erro.

🎯 Diagnósticos inline e QuickFixes (18 regras)

Análise estática sobre arquivos .py com códigos estilo Ruff (DOL001..DOL041), Applicability estilo Clippy e substituições de severidade por regra. .count() > 0 → .exists(), null=True em CharField, on_delete ausente, datetime.now() → timezone.now(), substituições de planner-GUC em SQL bruto (enable_*, plan_cache_mode, jit*; somente diagnóstico) e mais uma dúzia.

Suprima inline com # django-orm-lens-disable-next-line DOL007.

🧪 Gerador de factories

Clique com o botão direito em qualquer modelo → scaffold factory_boy DjangoModelFactory com provedores Faker baseados no tipo de campo. CharField(max_length) escala buckets de contagem de palavras, DecimalField(N,D) calcula left_digits=N-D, choices= mapeia para Iterator, M2M recebe @post_generation. Cadeias de FK puxam factories relacionadas transitivamente.

Também disponível como CodeLens acima de cada classe de modelo.

🕰 Diff de schema com viagem no tempo

Escolha um models.py, escolha dois commits, receba um diff tipado como markdown pronto para PR. Eventos AddModel / DropModel / RenameModel / ModifyModel com detecção de renomeação com pontuação de confiança (Levenshtein + Jaccard de forma de campo).

Renomeações são eventos de primeira classe, nunca Add + Drop. Cache LRU de Blob-SHA — commits que não tocam models.py compartilham seu snapshot analisado.

🔎 Análise de impacto

"O que quebra se eu remover este campo?" — clique com o botão direito em um campo ou modelo → varredura em todo o workspace agrupada por camada Django (models, serializers, forms, admin, views, urls, templates, tests, migrations).

Os resultados carregam uma etiqueta de confiança Certo / Provável / Possível. Lida com refs de string ORM (order_by("-author")), lookups de kwarg (filter(author__id=1)), tuplas Meta.fields e variáveis de template.

⚡ Construtor de consultas interativo

Clique com o botão direito em um campo ou modelo → escolha um template → snippet inserido no cursor (com tab-stops) ou em um buffer novo sem título.

.filter(field=?) em um FK anexa automaticamente .select_related(...), .annotate(post_count=Count('post_set')) honra related_name, .prefetch_related para M2M, .values('field').distinct(), .only('field').

🎨 Reformulação da barra lateral

TreeItem.id estável — atualizar não colapsa mais a árvore. Tooltips ricos de MarkdownString com deep-links de command:. Badges na barra de atividade contam problemas DOL###.

Badges FileDecorationProvider: ! vermelho em FK-sem-on_delete, ~ amarelo em campos de string null=True (propaga para a linha do Model pai, estilo Git).


📸 Como parece

VS Code with Django ORM Lens: the model tree, ORM diagnostics in views.py and the live ER diagram

Amostra ao vivo — saída real de django-orm-lens er, renderizada pelo GitHub aqui mesmo:

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]"

Também incluído na extensão:

  • 🕸️ Diagrama ER ao vivo — setas de cardinalidade Mermaid, rótulos de borda (CASCADE, through Model, as related_name), consciente de tema, exportação SVG com um clique
  • 🔎 Cartões de foco — sobre qualquer ForeignKey('app.Model') ou ManyToManyField(...), com link de salto em um clique
  • 🧭 CodeLens — acima de cada linha de class Model: contagem de campos, contagem de relações e uma ação Abrir diagrama ER
  • 🎨 Temas nomeados — auto / default / dark / forest / neutral para o webview do diagrama

🤖 Para terminais e agentes de IA de codificação

O mesmo parser que alimenta a extensão do VS Code é distribuído como um pacote Python independente — com um servidor MCP (Model Context Protocol) opcional, para que qualquer agente de IA compatível com MCP possa navegar pelo seu esquema Django sem importar o Django ou iniciar seu aplicativo.

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 list | fzf                   # flat app.Model — pipes anywhere
django-orm-lens er > schema.mmd              # ER diagram — Mermaid (default)
django-orm-lens er -f dbml > schema.dbml     # …or DBML: paste into dbdiagram.io
django-orm-lens er -f d2 > schema.d2         # …or D2 / plantuml / dot
django-orm-lens diff before.json after.json  # what a PR changes structurally
django-orm-lens nplusone --format github     # N+1 findings as PR annotations
django-orm-lens migration-risk -f sarif      # SARIF for GitHub Code Scanning
django-orm-lens suggest-indexes blog.Post    # Meta.indexes proposals from usage
django-orm-lens signals                      # sender→signal→handler graph
django-orm-lens migration-deps blog -f mermaid   # per-app migration DAG
django-orm-lens cascade blog.Author          # what one delete() takes down
django-orm-lens impact author                # what still references a field
django-orm-lens blast-radius -f markdown     # risks + who still reads them
django-orm-lens drift                        # migrations vs models, no boot
django-orm-lens stats-sql                    # read-only SQL for --stats

impact, blast-radius, drift e stats-sql são fornecidos na py-1.7.0 e versões posteriores.

Todo comando aceita --path <dir> e --exclude <glob>. nplusone / migration-risk / diff saem com código 1 quando há achados — use-os no CI para bloquear PRs com regressões.

Servidor MCP

Registre-o uma vez com seu agente e ele expõe treze ferramentas somente leitura:

FerramentaFinalidade
list_appsTodos os aplicativos Django no workspace com contagens de modelos
list_modelsLista plana de app.Model, com filtro opcional por aplicativo
describe_modelDetalhes completos de campo / relação / Meta para um modelo
find_relationsRelações de entrada e saída para um modelo
cascade_previewRaio de impacto de um delete(), agrupado por on_delete
er_diagramDiagrama ER — mermaid / dbml / d2 / plantuml / dot
describe_migration_dependencyDAG de migrações por aplicativo: raízes, folhas, dependências entre aplicativos
suggest_indexesPropostas de Meta.indexes a partir do uso observado de QuerySet
signal_graphGrafo remetente→sinal→handler a partir de decoradores @receiver
blast_radiusO que uma migração destrutiva atinge: seus riscos, o código que ainda a lê, o impacto em cascata
driftmakemigrations --check sem iniciar o Django — migrações comparadas com models.py
impactToda referência a um campo ou nome de modelo, agrupada por camada Django
nplusone_scanAchados estáticos de N+1 para todo o workspace
# Start it directly
django-orm-lens-mcp

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

Resolução de workspace (py-1.3.0+). Toda ferramenta aceita um argumento opcional workspace_root na chamada. Prioridade de resolução: argumento explícito → $DJANGO_ORM_LENS_ROOT → diretório de trabalho atual. Caminhos inválidos ou não-Django retornam um envelope estruturado ({"error": "WORKSPACE_NOT_DJANGO", "hint": "…"}) em vez de resultados vazios, para que o agente possa se autocorrigir. Sandbox opcional via DJANGO_ORM_LENS_ALLOWED_ROOTS (separado por ; no Windows, : em outros lugares).


🛡️ Proteja seu CI

Regressões de esquema são mais baratas de detectar no momento em que entram em um PR. Quatro maneiras sem configuração para bloqueá-las:

Bot de PR de raio de impacto — a revisão completa do esquema em um único comentário, atualizado no lugar a cada push em vez de um novo comentário a cada vez:

name: Schema review
on: pull_request

permissions:
  contents: read
  pull-requests: write        # only for `comment: true`

jobs:
  blast-radius:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: FROWNINGdev/django-orm-lens@action-v1
        with:
          command: blast-radius
          only-changed: true          # scope to migrations this PR touches
          comment: true               # post once, then update in place
          github-token: ${{ github.token }}

O comentário vai ao ar antes de o job falhar, então um PR bloqueado ainda explica o motivo. only-changed lê a lista de arquivos do PR da API em vez de git diff, porque actions/checkout usa como padrão fetch-depth: 1 e o commit base não está no histórico local. Em eventos push, ambas as flags pulam com um aviso em vez de falhar, então um único workflow cobre os dois gatilhos.

A Action instala a partir do PyPI, então blast-radius e drift precisam da py-1.7.0 ou posterior — fixe-a com version: 1.7.0 se seu workflow não puder variar. Para executar uma versão não publicada, adicione install: false e instale a fonte você mesmo; o workflow deste repositório faz exatamente isso, e é o que verifica a Action em todo PR.

pre-commit — dois hooks, nada para instalar localmente:

# .pre-commit-config.yaml
repos:
  - repo: https://github.com/FROWNINGdev/django-orm-lens
    rev: py-v1.13.0
    hooks:
      - id: django-orm-lens-nplusone
      - id: django-orm-lens-migration-risk

GitHub Action — os achados aparecem como anotações de PR com zero permissões extras:

- uses: FROWNINGdev/django-orm-lens@action-v1
  with:
    command: migration-risk      # or: nplusone
    format: github               # ::error / ::warning annotations on the diff

SARIF → Code Scanning — os achados vão para a aba Segurança do repositório:

- run: |
    pip install django-orm-lens
    django-orm-lens migration-risk --format sarif --exit-zero > lens.sarif
- uses: github/codeql-action/upload-sarif@v3
  with:
    sarif_file: lens.sarif

Os códigos de saída são nativos de CI: diff e nplusone saem com 1 em achados, migration-risk e blast-radius saem com 1 em achados críticos, drift sai com 1 quando um campo é declarado mas nunca migrado. Adicione --exit-zero para o modo somente relatório.


🔌 Integrações

ClienteComo habilitarStatus
VS Codecode --install-extension frowningdev.django-orm-lens✅
Cursormesmo VSIX + entrada MCP opcional em ~/.cursor/mcp.json✅
Windsurf / VSCodium / qualquer fork do Codeinstale o VSIX do Marketplace ou dos GitHub Releases✅
Aideradicione django-orm-lens-mcp ao seu mcp.json✅ (via MCP)
Continue.devregistre o servidor MCP em ~/.continue/config.json✅ (via MCP)
Zedregistre o servidor MCP nas configurações do Zed✅ (via MCP)
Qualquer cliente compatível com MCPaponte command para django-orm-lens-mcp, defina DJANGO_ORM_LENS_ROOT✅
pre-commitrepo: https://github.com/FROWNINGdev/django-orm-lens + dois IDs de hook✅
GitHub Actionsuses: FROWNINGdev/django-orm-lens@action-v1 — anotações ou SARIF✅
Descobrível via MCP Registrydiretório oficial de servidores Model Context Protocol✅
Terminal simples / CIpip install django-orm-lens && django-orm-lens scan✅

Exemplo: Cursor / qualquer cliente MCP

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

⚡ Desempenho

A suíte de regressão analisa os grafos de modelos vendidos de Zulip, Saleor, Wagtail, django CMS e Mezzanine — 59 modelos em 13.478 linhas de models.py do mundo real — em cerca de 20 ms de ponta a ponta em um laptop (21 ms melhor-de-3 no corpus de fixtures douradas do repositório; um guard de <2 s roda no CI em cada célula da matriz).

Reproduza você mesmo:

git clone https://github.com/FROWNINGdev/django-orm-lens && cd django-orm-lens/cli
pip install -e . && python -m pytest tests/test_golden_fixtures.py tests/test_golden_snapshots.py -q

🎯 Para quem é isso

  • Desenvolvedores Django que entram em um codebase com 10+ aplicativos e se perdem na bagunça de models.py.
  • Engenheiros contratados / freelancers que precisam entender um projeto Django desconhecido na primeira hora, não na primeira semana.
  • Equipes integrando novos contratados que querem uma visão de esquema em um relance sem montar infraestrutura de documentação.
  • Usuários avançados de agentes de IA (Cursor / Aider / Zed / Continue / qualquer cliente compatível com MCP) que precisam que o agente responda perguntas de esquema com precisão — sem dar a ele credenciais de banco de dados ou iniciar o Django.
  • Pipelines de CI que verificam a forma do esquema (por exemplo, "quebramos acidentalmente um related_name?") sem importar o projeto.
  • Devs indie solo com um venv quebrado ou no laptop de outra pessoa — sem runserver, sem manage.py migrate, ainda funciona.

🗺️ Posição de mercado

Django ORM Lens fica na interseção de ferramentas de editor e ferramentas de agente de IA — um espaço que nenhum pacote existente cobre:

SegmentoOpção existenteO que custa para você
Iniciar-e-grafodjango-extensions graph_modelsRequer Graphviz + configurações do Django + uma URL de banco funcional
Visualizador baseado na webdjango-schema-graphRequer um servidor Django em execução; hospeda mais uma coisa para quebrar
Painel administrativoDjango AdminRequer runserver + autenticação + banco de dados — ótimo para dados, não para arquitetura
Plugin de editorEstrutura Django do PyCharmLimitado ao PyCharm; sem CLI, sem história de agente de IA
Servidor MCP(nenhum até agora)Agentes de IA adivinham seu esquema a partir do código-fonte, de forma imperfeita

Django ORM Lens é a única ferramenta que oferece três superfícies a partir de um único parser: uma extensão do VS Code (qualquer fork do Code), uma CLI sem dependências (terminais + CI) e um servidor MCP (agentes de IA). Tudo estático. Tudo gratuito. Tudo MIT.


🤔 Como isso é diferente?

Django ORM Lensdjango-extensions graph_modelsdjango-schema-graphDjango AdminEstrutura Django do PyCharm
Funciona sem um projeto Django inicializável✅❌❌❌⚠️
Sem instalação (sem graphviz, sem servidor)✅❌❌❌❌ (precisa do PyCharm)
Funciona no VS Code / Cursor / qualquer fork do Code✅❌❌❌❌
Árvore lateral dentro do editor✅❌❌❌✅
Diagrama ER ao vivo✅✅✅❌❌
Cartões de foco em ForeignKey✅❌❌❌⚠️
CodeLens em classes de modelo✅❌❌❌❌
Suporte a pacote models/ dividido✅⚠️⚠️✅✅
CLI para terminal / CI✅⚠️❌❌❌
Servidor MCP para agentes de IA✅❌❌❌❌
Descobrível no MCP Registry✅❌❌❌❌
Gratuito e de código aberto (MIT)✅✅✅✅❌ (IDE paga)
Suporte a versões do Django4.0 – 5.2mais recente3.2 – 4.1 (desatualizado desde 2023)mais recentemais recente

django-schema-graph não é atualizado desde 2023-05 e não testa Django 5.x.

Quando você quer outra coisa

Limites honestos: perfil de uma requisição ao vivo → django-debug-toolbar. Perfil histórico de requisições → django-silk. Asserções de contagem de consultas dentro de uma suíte de testes → django-perf-rec. APM de produção em tráfego real → Scout / Sentry. Django ORM Lens permanece deliberadamente estático — é a camada que funciona antes mesmo de o aplicativo iniciar, e a única que seu CI e seu agente de IA podem usar em qualquer checkout.


⚙️ Configuração

Os padrões são opinativos e sensatos. Se precisar ajustar:

// .vscode/settings.json
{
  "djangoOrmLens.excludeGlobs": [
    "**/migrations/**",
    "**/node_modules/**",
    "**/venv/**",
    "**/.venv/**",
    "**/env/**"
  ],
  "djangoOrmLens.autoRefresh": true
}
ConfiguraçãoTipoPadrãoO que faz
djangoOrmLens.excludeGlobsstring[]Veja acimaPadrões glob para pular ao escanear
djangoOrmLens.autoRefreshbooleantrueReescaneia em mudanças de models.py
djangoOrmLens.codeFixes.enabledbooleantrueInterruptor mestre para os diagnósticos DOL### + QuickFixes
djangoOrmLens.rulesobject{}Severidade por regra: { "DOL007": "off", "DOL013": "error" }
djangoOrmLens.rulesSelectstring[][]Seleção estilo Ruff. ["DOL0"] executa apenas regras de queryset+modelo
djangoOrmLens.rulesIgnorestring[][]Ignorar estilo Ruff. ["DOL03"] silencia regras de formulário/visão

🔬 Catálogo de regras

Dezoito verificações do lado do editor (DOL001–DOL041) com códigos estilo Ruff, severidade por regra e aplicabilidade estilo Clippy — além de dezesseis regras de risco de migração do lado da CLI e o analisador estático de N+1. Toda regra agora tem sua própria página de documentação.

CategoriaRegrasExemplos
QuerysetDOL001–DOL007.count() > 0 → .exists(), acesso a FK em loops (N+1)
Definição de modeloDOL011–DOL015ForeignKey sem on_delete, null=True em campos de string
DatetimeDOL021–DOL022datetime.now() → timezone.now()
Formulários / visõesDOL031–DOL032locals() em render(), Meta.fields = '__all__'
SQL brutoDOL041SET enable_hashjoin = off, plan_cache_mode, jit overrides em código de aplicativo
Riscos de migração16 regrasNOT NULL adicionado sem padrão, builds de índice com bloqueio de tabela, migrações de dados irreversíveis
N+1 estático1 analisadorAcesso a FK/M2M em loops sem select_related / prefetch_related

→ Referência completa de regras — todo código com exemplos ruins/bons, comportamento do QuickFix e sintaxe de supressão.

Suprimir 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

A aplicabilidade segue o Clippy do Rust: correções seguras podem ser aplicadas automaticamente ("Corrigir tudo"), correções sugeridas são oferecidas como QuickFix, mas revisadas, achados inseguros nunca são aplicados automaticamente. As correções são separadas dos analisadores (estilo Roslyn), então uma regra pode ganhar vários corretores ao longo do tempo sem tocar na lógica de detecção.


🧭 Comandos

Abra a paleta de comandos (Ctrl+Shift+P / Cmd+Shift+P) e digite "Django ORM Lens":

ComandoO que faz
Django ORM Lens: RefreshForça o reescaneamento do workspace
Django ORM Lens: Show ER DiagramAbre o diagrama ER Mermaid lado a lado
Django ORM Lens: Filter ModelsFiltra a árvore por nome de app / modelo / campo
Django ORM Lens: Clear FilterRestaura a árvore completa
Django ORM Lens: Jump to ModelProgramático — acionado por cliques na árvore e cards de hover
Django ORM Lens: Find Reverse ReferencesClique com o botão direito em um modelo — QuickPick de cada FK apontando para ele
Django ORM Lens: Generate factory_boy FactoryClique com o botão direito em um modelo ou use CodeLens — gera um scaffold de DjangoModelFactory
Django ORM Lens: Schema Diff (Time-Travel)Escolha dois commits — obtenha um diff tipado como buffer markdown
Django ORM Lens: Find Impact (What Uses This?)Clique com o botão direito em um campo ou modelo — varredura de referências em todo o workspace
Django ORM Lens: Build Query (Insert Snippet)Clique com o botão direito em um campo ou modelo — escolha um template ORM

🗺️ Roadmap

Entregue

  • Árvore da barra lateral agrupada por app
  • Diagrama ER Mermaid ao vivo
  • Cards de hover sobre ForeignKey('app.Model')
  • Filtro da árvore por nome
  • Suporte a pacotes divididos models/
  • Exportação do diagrama ER como SVG
  • CLI Python + servidor MCP para terminais e agentes de IA
  • Visualização de boas-vindas para workspaces vazios
  • Ir para definição seguro para caminhos e markdown de hover sanitizado
  • v0.3.0 — CodeLens acima de cada classe de modelo (N fields · N relations · Open ER diagram)
  • v0.3.0 — Rótulos de arestas no diagrama (CASCADE, SET_NULL, PROTECT, related_name)
  • v0.3.0 — Temas de cores nomeados (auto / default / dark / forest / neutral)
  • v0.3.1 — through_model em arestas M2M (contribuição de @kingrubic)
  • v0.3.1 — Listado no Registro MCP oficial + Glama.ai
  • v0.6.0 — CLI nplusone — detector estático de N+1 (acesso a FK/M2M dentro de loops sem select_related/prefetch_related)
  • v0.6.0 — CLI migration-risk — sinaliza operações arriscadas em migrations/*.py (15 regras hoje)
  • v0.6.0 — CLI diff — compara dois dumps de schema JSON para revisão de PR
  • v0.6.0 — Minimapa do diagrama ER codifica por cores os nós por app Django
  • v0.6.0 — Traduções do README: 🇷🇺 Russo, 🇪🇸 Espanhol, 🇨🇳 Chinês
  • v0.6.0 — Imagem Docker no GHCR: docker run ghcr.io/frowningdev/django-orm-lens
  • v0.7.0 — settings.AUTH_USER_MODEL resolve em todos os lugares: relações reversas n+1, remetentes de sinais, Mermaid ER, webview do VS Code, painel de relações de entrada, ER React
  • v0.7.0 — Parser de campos baseado em AST: ForeignKey(on_delete=CASCADE, to='User') resolve independentemente da ordem dos kwargs (paridade Python + TS)
  • v0.7.0 — Helpers compartilhados públicos: find_user_model, resolve_related_tail, find_model, iter_workspace_py_files (Python) + findUserModel, resolveRelatedTail (TS)
  • v0.7.0 — --verbose não percorre mais a árvore duas vezes; WorkspaceIndex.scanned_files carrega a contagem
  • v0.7.3 — Anotações de tipo PEP-526 em campos (jti: CharField[str] = models.CharField(...)) agora são analisadas — relatado por @jsabater (#25) com um repro limpo do Django Ninja 1.6
  • v0.7.4 — Cabeçalhos de classe genéricos PEP-695 (Python 3.12+): class Container[T](models.Model): agora é analisado
  • v0.7.5 — Módulo de modelos com alias (from django.db import models as m) e pacotes de campos de terceiros (jsonfield.JSONField) agora são detectados
  • v0.7.6 — Corpos de modelo indentados com tabulação agora são analisados (editores que usam tabs por padrão não mostram mais modelos vazios)
  • v0.8.0 — QuickFixes inline: 16 regras (DOL001..DOL032) com severidade por regra + selecionar/ignorar estilo Ruff + # django-orm-lens-disable-next-line inline
  • v0.8.0 — Gerador de factories: scaffold factory_boy a partir de qualquer modelo com provedores Faker chaveados por tipo de campo
  • v0.8.0 — Diff de Schema com Viagem no Tempo: escolha dois commits → diff markdown tipado com detecção de renomeação de primeira classe
  • v0.8.0 — Análise de impacto: varredura de referências de campos em todo o workspace em cada camada Django com tags de confiança Certa/Provável/Possível
  • v0.8.0 — Construtor de Consultas Interativo: clique com o botão direito → template → snippet inserido no cursor, ciente da gramática (FK recebe .select_related, related_name respeitado)
  • v0.8.0 — Reformulação da UX da barra lateral: TreeItem.id estável, tooltips MarkdownString com deep-links command:, badges FileDecorationProvider, TreeView.badge na barra de atividades, três estados viewsWelcome com gate por condição

v1.5.0 — a onda "um núcleo, três superfícies"

  • CI formata: SARIF 2.1.0 + anotações de PR --format github para nplusone e migration-risk
  • Quatro analisadores promovidos de somente-MCP para o CLI: suggest-indexes, signals, migration-deps, cascade
  • er --format dbml | d2 | plantuml | dot — exportações de diagramas padrão da comunidade (dbdiagram.io, D2, PlantUML, Graphviz — dot contribuído por @JJordan0C)
  • Três novas regras de risco de migração: runpython_no_reverse, alter_unique_together_lock, alter_index_together_deprecated — 15 no total
  • Hooks de pre-commit (django-orm-lens-nplusone, django-orm-lens-migration-risk) + GitHub Action composta
  • docs/rules/ — uma página de documentação para cada regra (19 páginas)
  • Suíte de regressão com snapshots dourados sobre 59 modelos reais (Zulip / Saleor / Wagtail / django CMS / Mezzanine); ruff + mypy agora controlam o CI
  • Grafo de dependências de migração — migration-deps (texto / json / mermaid)

py-1.7 → 1.8 — a onda de inteligência de schema

  • blast-radius — riscos de migração unidos ao que ainda lê o schema que eles tocam, como bot de PR (comment: true, fixado, only-changed)
  • drift — makemigrations --check sem iniciar o Django
  • impact <name> — o que ainda referencia um modelo ou campo, agrupado por camada Django
  • blast-radius --stats + stats-sql — contagens opcionais de linhas de produção a partir de SQL somente-leitura que você mesmo executa (a ferramenta nunca guarda credencial de banco)
  • nplusone resolve entre funções — um queryset retornado por um helper é seguido até o loop que o consome
  • blast_radius, drift e impact expostos como ferramentas MCP — treze ferramentas para agentes de IA
  • drift documenta suas marcas !! / ~ no relatório e em --help — relatado por @sevdog (#57)
  • drift segue herança de bases abstratas — os campos de uma base abstrata contam como os do filho concreto, como o Django os trata — relatado por @sevdog (#58)
  • suggest-index reconhece os índices que o Django já criou — chave primária (pk e id são uma única consulta), db_index, unique, chaves estrangeiras, unique_together, UniqueConstraint — relatado por @sevdog (#60), mesma causa encontrada independentemente por @RinZ27 (#61)
  • Uma sexta fixture dourada — Read the Docs se junta a Zulip, Saleor, Wagtail, django-CMS e Mezzanine, colocando o parser sob 75 modelos e 538 campos de Django real — contribuído por @JJordan0C (#62, fechando #51)
  • O TaggableManager do django-taggit é lido como o M2M que ele é — através de taggit.TaggedItem para taggit.Tag, overrides through= respeitados, tanto no parser Python quanto no TypeScript — contribuído por @Guflly (#63, fechando #50)
  • DOL021 declara o padrão USE_TZ corretamente — False até Django 4.2, True a partir de 5.0, com o USE_TZ = True do template startproject desde 4.0 destacado como a coisa separada que é — e não afirma mais que timezone.now() está sempre ciente de UTC — encontrado por @Justine0211 enquanto traduzia a página (#52)
  • A fixture parity_input.py carrega o import models que um models.py real teria — contribuído por @RinZ27 (#64)

py-1.9 → 1.12 — a onda de checkouts reais

Encontrado executando o CLI sobre checkouts reais de django-oscar, django-guardian, django-allauth e django-cms em vez de fixtures. Cada um desses era invisível para uma suíte de testes verde, e dois deles faziam a ferramenta responder com confiança algo falso.

  • Modelos declarados dentro de um bloco no nível do módulo são analisados — o idioma de modelo trocável (if not is_model_registered(...): e depois um class indentado) que todo framework Django plugável usa, contra a descoberta de classes ancorada em ^class. django-oscar passou de 12 modelos, todos do seu próprio diretório tests/, para 82. Todos os seis snapshots dourados permaneceram byte-idênticos: uma classe na coluna 0 é analisada exatamente como antes
  • abstract_models.py é lido junto com models.py — frameworks plugáveis mantêm a base abstrata lá e deixam models.py segurando apenas a subclasse concreta, então 72 dos 83 modelos do django-oscar reportavam zero campos entre eles. Agora são 8, e esses 8 estão corretos: eles subclassificam modelos concretos, onde a herança multi-tabela deixa as colunas na tabela do pai
  • drift não falha mais um build por dois diretórios de app compartilhando o mesmo nome — o estado de migração reproduzido é mesclado por nome de app, combinando com como o lado declarado já é chaveado. Em um checkout real do django-guardian, a contagem de bloqueios vai de 1 → 0 e a linha duplicada contraditória desaparece, enquanto um campo genuinamente não migrado ainda bloqueia
  • Modelos django-mptt não são mais invisíveis — MPTTModel é uma base reconhecida, e TreeForeignKey / TreeOneToOneField / TreeManyToManyField são reportados como os campos Django que eles subclassificam, então TreeForeignKey('self', ...) desenha exatamente a auto-aresta que um ForeignKey('self', ...) simples faz. Nenhuma dependência django-mptt é adicionada — o parser continua funcionando contra um venv quebrado. O product.Category do Saleor e sua aresta children agora aparecem no snapshot dourado: 76 linhas adicionadas, nenhuma removida (fechando #49)
  • O servidor MCP reporta sua própria versão — FastMCP não encaminha nenhuma, então o SDK caía para importlib.metadata.version("mcp") e cada resposta initialize nomeava o número de release do projeto errado para o cliente

v0.9 → v0.12.1 — a extensão alcança

  • v0.9.0 — Rastreamento parcial de UniqueConstraint no Time-Travel Schema Diff: add / drop / change / rename como eventos tipados, com fromCondition carregando o predicado anterior à mudança, para que um comentário de revisão possa mostrar Q(is_primary=True) → Q(is_primary=True, deleted=False), e uma renomeação não aparecendo mais como um par add + drop com perda de dados. Várias restrições sem nome em um único modelo são agrupadas em #anon-<index> em vez de colapsarem em um único evento. Motivado por django-extensions #1813, onde sqldiff descarta o predicado condition= e os revisores de migração nunca veem o que mudou
  • v0.10.0 — A detecção de camadas da análise de impacto agora roda no caminho relativo ao workspace. Antes, ela correspondia a /tests/ e /views.py em qualquer lugar no caminho absoluto do arquivo, então um projeto clonado em qualquer diretório chamado tests — ou um monorepo com services/tests/ acima — fazia todos os arquivos serem reportados como aquela camada, views.py como teste, admin.py como teste. Também: mensagens do webview validadas por origem em vez de por fonte, e migrações folha conflitantes detectadas — duas migrações reivindicando o mesmo pai, algo que o Django só reclama na hora de migrate
  • v0.10.1 — A listagem no Marketplace menciona análise de impacto, raio de explosão e deriva de esquema, e diz claramente que a ferramenta é gratuita e MIT, sem camada Pro. A página da loja ainda descrevia a extensão como uma barra lateral e um diagrama ER — o que ela era duas versões atrás — então ninguém que buscava esses recursos a encontrava. Os metadados só têm efeito na publicação, por isso precisou de um lançamento próprio
  • v0.11.0 — A metade TypeScript do suporte a django-mptt, lançada como versão própria em vez de incorporada a uma posterior: entre o envio do py-1.12.0 e este build, a CLI e a extensão discordavam sobre o que um esquema django-mptt contém, que é exatamente a falha que o fixture dourado compartilhado existe para evitar
  • v0.12.0 — A extensão pede uma estrela no GitHub na terceira abertura iniciada pelo usuário do diagrama ER. Não na instalação: um aviso que chega antes de a ferramenta ter feito qualquer coisa é dispensado reflexivamente, e essa dispensa é permanente na mente do usuário. Atualizações da barra lateral que re-renderizam um painel já aberto não são contadas — não são o usuário pedindo nada. "Depois" e "Não perguntar de novo" são armazenados como estados separados, então um adiamento rearma a pergunta exatamente uma vez, doze aberturas depois; dois avisos é o máximo por vida útil. A política é uma função pura coberta por seis testes que não precisam de host VS Code
  • v0.12.1 — Exportar como SVG gravava um arquivo inaberto. toSvg retorna marcação com codificação percentual, enquanto toPng retorna base64; o caminho de salvamento assumia base64 para qualquer coisa começando com data:, e decodificar base64 de texto com codificação percentual não falha — o decodificador descarta silenciosamente todo caractere fora do seu alfabeto e retorna bytes. Um documento <svg> de 48 caracteres chegava ao disco com o nome certo, um tamanho plausível e nenhum conteúdo válido em lugar algum. A codificação de transferência agora é lida do cabeçalho da URL de dados em vez de adivinhada pelo prefixo

Próximo

  • v0.13.0 — Autocompletar campos dentro de .filter() / .exclude() / .get() (#3)
  • v0.10.0 — Caixas de seleção de app / modelo: desmarque um app ou modelo na barra lateral para removê-lo do diagrama ER
  • Mecanismo de regras DOL portado para a CLI Python — um catálogo de regras, três superfícies

Depois

  • Suporte a campos de terceiros — django-model-utils (django-taggit enviado no py-1.11.0, django-mptt no py-1.12.0 / v0.11.0)
  • Plugin JetBrains / PyCharm (se houver demanda)

Vote com 👍 na issue correspondente.


❓ FAQ

Você envia algum dos meus códigos para um servidor?
Não. Cada byte permanece na sua máquina. O parser é TypeScript puro (extensão) ou Python puro (CLI). Sem chamadas de LLM, sem telemetria, sem analytics, sem relatórios de erro. O renderizador Mermaid roda dentro do sandbox do webview do VS Code.
Funciona com Poetry / uv / conda / sem venv algum?
Sim. A extensão lê o código-fonte Python diretamente — ela não importa o Django e não se importa com qual gerenciador de pacotes você usa. A CLI exige Python 3.9+, mas só isso.
Meus modelos estão divididos em vários arquivos dentro de um pacote models/. Isso funciona?
Sim, desde a v0.2.0. Tanto a extensão quanto a CLI percorrem models/*.py além do clássico models.py.
Posso usar com serializers DRF, Wagtail, Oscar ou modelos base de terceiros?
Qualquer classe que pareça um modelo Django é capturada: subclasses de models.Model, bases abstratas começando com Abstract, mixins comuns terminando em Mixin, e nomes de base conhecidos como TimeStampedModel ou PolymorphicModel. Classes que não são modelos (ModelAdmin, ModelSerializer, Form, View, Manager, …) são filtradas.
Quais agentes de IA podem usar o servidor MCP?
Qualquer cliente compatível com MCP — Cursor, Aider, Continue.dev, Zed e qualquer outra ferramenta que fale o protocolo. Basta apontar command para o binário instalado django-orm-lens-mcp. Veja a seção Integrations.
Como bloqueio regressões de esquema no CI?
Três maneiras, todas sem configuração: os dois pre-commit hooks, a GitHub Action composta (uses: FROWNINGdev/django-orm-lens@action-v1 com format: github para anotações em PRs), ou --format sarif canalizado para github/codeql-action/upload-sarif na aba Segurança. diff / nplusone saem com código 1 em achados, migration-risk sai com código 1 em achados críticos.
Existe uma versão JetBrains / PyCharm?
Ainda não. A janela de ferramentas Django Structure do PyCharm já é boa, então o delta de valor é menor. Se gente suficiente pedir, vale a pena fazer.

🆘 Suporte


📜 Licença

MIT © FROWNINGdev


Feito para desenvolvedores que se importam com seu código.

Marketplace · PyPI · GitHub · Issues · Discussions · Patrocinar