Django ORM Lens

Análisis estático de esquemas Django para agentes de IA: 10 herramientas de solo lectura (modelos, relaciones, diagramas ER, DAG de migraciones, escaneo N+1) sin base de datos y sin arranque de Django.

Documentación

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

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

Django ORM Lens

Diagramas ER, detección de N+1 y comprobaciones de riesgo de migración para Django — sin iniciarlo.

Todo tu grafo de modelos — en vivo en la barra lateral de tu editor, controlando tu CI y respondiendo a tu agente de IA a través de MCP. Todo desde análisis estático: sin base de datos, sin runserver, sin venv funcional.

Reemplaza: graph_models + django-schema-graph + diagramas ER dibujados a mano + arqueología con grep.


PyPI Python Django versions CI Downloads License


Install on VS Code Install on Open VSX Docker GHCR


Destacado en Django News #347 · PyCoder's Weekly #746


⚡ 10 segundos hasta la primera idea

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

Clon en frío, venv roto, sin módulo de configuración — aún así ves cada app y modelo del proyecto, luego los bucles N+1 y las migraciones arriesgadas, directamente en tu terminal. (uvx es de uv; pipx run funciona igual.)

Luego elige tu superficie — tres distribuciones, un núcleo de análisis:

EresInstalaciónObtienes
Usuario de editor — VS Code / Cursor / Windsurf / VSCodiumcode --install-extension frowningdev.django-orm-lensAutocompletado de campos en .filter(), árbol en barra lateral, diagrama ER en vivo, tarjetas al pasar el cursor, 18 reglas de lint con QuickFixes
Usuario de terminal / CIpip install django-orm-lens17 subcomandos, SARIF + anotaciones de PR, hooks de pre-commit, una GitHub Action
Usuario de agente de IA — Cursor / Claude Code / Aider / Zed / Continuepip install "django-orm-lens[mcp]"13 herramientas MCP de solo lectura que responden preguntas de esquema desde la fuente de verdad

La configuración de MCP es un bloque JSON — ver Integraciones. Apunta DJANGO_ORM_LENS_ROOT a la ruta absoluta de tu proyecto Django.


🆓 Capacidades de nivel de pago, gratis y MIT

La revisión de esquemas es una categoría de pago en casi todas partes. Un bot que revisa cada pull request, análisis que sigue un queryset más allá de la función donde se creó, una comprobación que detecta deriva de esquema, consejos de índices basados en estadísticas reales de tablas — todo eso normalmente está detrás de una suscripción por asiento o por base de datos.

Todo está aquí, con licencia MIT, sin límite de nivel, sin conteo de asientos, sin cuenta y sin telemetría:

Capacidad normalmente vendida como nivel de pagoAquí
Bot de revisión de PR para cambios de esquema — publica una vez, luego actualiza en el lugarblast-radius + la Action
Análisis que sigue un queryset a través de funcionesnplusone
Detección de deriva de esquemadrift
Propuestas de índices desde el uso observado de QuerySetsuggest-indexes
Riesgo de migración ponderado contra tamaños reales de tablasblast-radius --stats
Radio de impacto de una migración destructivablast-radius
Impacto entre capas de eliminar un campoimpact

No hay nivel Pro, y no está planeado. Si la herramienta te ahorra una tarde, una estrella es todo lo que pedimos.


📊 Tracción

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

Si la herramienta te ahorra un grep la próxima vez que toques un proyecto Django desconocido — una estrella ayuda a otros a encontrarla.

📈 Crecimiento de estrellas


⚡ Instalación

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

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

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

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

O busca Django ORM Lens en la vista de Extensiones — mismo editor frowningdev en ambos registros.

Agentes de terminal y de codificación con IA:

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

Requiere Python 3.9+. Cero dependencias de ejecución para la CLI.

Docker (v0.6+):

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

Multi-arquitectura (amd64 + arm64). No se requiere Python en el host. Ideal para CI y auditorías puntuales.


🎯 El problema

Funciona sin conexión. Funciona con un venv roto. Funciona en el portátil de otra persona. Funciona en CI.

Abres un proyecto Django. Tiene 20 apps. Necesitas responder una pregunta simple:

"¿Qué app es dueña del modelo Order, y cómo está conectado a User?"

Hoy, eso significa: Ctrl+P, "models", desplazarte por 30 resultados, abrir cinco archivos, Ctrl+F para class Order, leer 400 líneas de cadenas ForeignKey('otherapp.Something'), intentar recordar lo que aprendiste hace dos archivos.

Medio día perdido. Cada vez. En cada proyecto.


✨ Con Django ORM Lens

📚 Un árbol de todo

Cada app → cada modelo → cada campo → cada opción Meta. Agrupado por aplicación, ordenado alfabéticamente, expandible.

Los iconos distinguen CharField de ForeignKey de ManyToManyField de un vistazo.

🕸️ Un diagrama ER en vivo

Un comando abre un diagrama de entidad-relación Mermaid de todo tu esquema. Observa cómo se redibuja mientras editas. Exporta a SVG.

ForeignKey, OneToOneField y ManyToManyField se convierten en flechas de cardinalidad adecuadas.

🔎 Pasa el cursor para ver relaciones

Pasa el cursor sobre ForeignKey('app.Model') en cualquier archivo Python → aparece una tarjeta con los campos del modelo objetivo, sus relaciones y un enlace "Ir a". Sin Ctrl+F, sin diálogo de archivos.

🧭 Ir a la definición

Haz clic en cualquier campo del árbol → el cursor aterriza en la línea exacta. Filtra el árbol por nombre de app o modelo. Los paquetes divididos models/ son totalmente compatibles.

⚡ Cero configuración

Sin DJANGO_SETTINGS_MODULE. Sin runserver. Analiza models.py estáticamente. Funciona con un venv roto, una dependencia faltante o en el portátil de otra persona.

🎨 Interfaz nativa de VS Code

Tema oscuro. Tema claro. Tu tema. Sigue tu tema de iconos, tu fuente, tus atajos de teclado. Nada llamativo, nada de marca.


🚀 Funciones avanzadas

💥 Radio de impacto

La pregunta en tiempo de revisión que un cambio de esquema realmente plantea: ¿qué afecta esto? Cada operación de migración destructiva se convierte en un objetivo que lleva sus riesgos, cada lugar en el código que aún lo lee y — para operaciones de modelo completo — el efecto en cascada.

migration-risk, impact y cascade responden cada uno un tercio de eso; nadie los une a mano, así que la herramienta lo hace. --format markdown es un comentario de PR publicable; --stats convierte "probablemente poblado" en ~41 000 000 rows, 12.0 GB a partir de una consulta de solo lectura que ejecutas tú mismo, sin credenciales de base de datos cerca del CI.

🧭 Deriva de esquema

makemigrations --check sin iniciar Django. Las migraciones de cada app se reproducen en orden en el conjunto de campos que implican, y luego se comparan con lo que models.py declara.

La propia comprobación de Django necesita un módulo de configuración funcional, un registro de apps importable y todas las dependencias instaladas — no disponible en un clon en frío o un venv roto, que es exactamente cuando la respuesta es más barata de actuar. Solo la dirección peligrosa falla la compilación: un campo declarado pero nunca migrado significa que la columna no existirá, y la primera consulta que lo toca da error.

🎯 Diagnósticos en línea y QuickFixes (18 reglas)

Análisis estático sobre archivos .py con códigos estilo Ruff (DOL001..DOL041), Applicability estilo Clippy y anulaciones de severidad por regla. .count() > 0 → .exists(), null=True en CharField, falta on_delete, datetime.now() → timezone.now(), anulaciones de GUC de planificador en SQL crudo (enable_*, plan_cache_mode, jit*; solo diagnóstico), y una docena más.

Suprime en línea con # django-orm-lens-disable-next-line DOL007.

🧪 Generador de factories

Clic derecho en cualquier modelo → factory_boy DjangoModelFactory scaffold con proveedores de Faker según el tipo de campo. CharField(max_length) escala cubos de recuento de palabras, DecimalField(N,D) calcula left_digits=N-D, choices= mapea a Iterator, M2M obtiene @post_generation. Las cadenas FK arrastran factories relacionados transitivamente.

También disponible como CodeLens sobre cada clase de modelo.

🕰 Diff de esquema con viaje en el tiempo

Elige un models.py, elige dos commits, obtén un diff tipado como markdown listo para PR. Eventos AddModel / DropModel / RenameModel / ModifyModel con detección de renombres con puntuación de confianza (Levenshtein + Jaccard de forma de campo).

Los renombres son eventos de primera clase, nunca Add + Drop. Caché LRU de Blob-SHA — los commits que no tocan models.py comparten su instantánea analizada.

🔎 Análisis de impacto

"¿Qué se rompe si elimino este campo?" — clic derecho en un campo o modelo → escaneo de todo el espacio de trabajo agrupado por capa de Django (models, serializers, forms, admin, views, urls, templates, tests, migrations).

Los hallazgos llevan una etiqueta de confianza Cierto / Probable / Posible. Maneja referencias de cadena ORM (order_by("-author")), búsquedas de kwargs (filter(author__id=1)), tuplas Meta.fields y variables de plantilla.

⚡ Constructor de consultas interactivo

Clic derecho en un campo o modelo → elige una plantilla → snippet insertado en el cursor (con tab-stops) o en un buffer nuevo sin título.

.filter(field=?) en un FK agrega automáticamente .select_related(...), .annotate(post_count=Count('post_set')) respeta related_name, .prefetch_related para M2M, .values('field').distinct(), .only('field').

🎨 Renovación de la barra lateral

TreeItem.id estable — la actualización ya no colapsa el árbol. Tooltips ricos MarkdownString con enlaces profundos command:. Insignias en la barra de actividad cuentan problemas DOL###.

Insignias FileDecorationProvider: rojo ! en FK sin on_delete, amarillo ~ en campos de cadena null=True (se propaga a la fila del Modelo padre, estilo Git).


📸 Cómo se ve

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

Muestra en vivo — salida real de django-orm-lens er, renderizada por GitHub aquí mismo:

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

También incluido en la extensión:

  • 🕸️ Diagrama ER en vivo — flechas de cardinalidad Mermaid, etiquetas de bordes (CASCADE, through Model, as related_name), consciente del tema, exportación SVG con un clic
  • 🔎 Tarjetas flotantes — sobre cualquier ForeignKey('app.Model') o ManyToManyField(...), con un enlace de salto de un clic
  • 🧭 CodeLens — encima de cada línea de class Model: recuento de campos, recuento de relaciones y una acción Abrir diagrama ER
  • 🎨 Temas con nombre — auto / default / dark / forest / neutral para la vista web del diagrama

🤖 Para terminales y agentes de IA de codificación

El mismo analizador que impulsa la extensión de VS Code se distribuye como un paquete Python independiente, con un servidor MCP (Model Context Protocol) opcional para que cualquier agente de IA compatible con MCP pueda navegar por tu esquema de Django sin importar Django ni iniciar tu aplicación.

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 y stats-sql se incluyen en py-1.7.0 y versiones posteriores.

Cada comando acepta --path <dir> y --exclude <glob>. nplusone / migration-risk / diff salen con código 1 si hay hallazgos: úsalos en CI para bloquear PRs por regresiones.

Servidor MCP

Regístralo una vez con tu agente y expone trece herramientas de solo lectura:

HerramientaPropósito
list_appsCada aplicación de Django en el espacio de trabajo con recuentos de modelos
list_modelsLista plana de app.Model, filtro opcional por aplicación
describe_modelDetalle completo de campos / relaciones / Meta para un modelo
find_relationsRelaciones entrantes y salientes para un modelo
cascade_previewRadio de impacto de un delete(), agrupado por on_delete
er_diagramDiagrama ER — mermaid / dbml / d2 / plantuml / dot
describe_migration_dependencyDAG de migraciones por aplicación: raíces, hojas, dependencias entre aplicaciones
suggest_indexesPropuestas de Meta.indexes a partir del uso observado de QuerySet
signal_graphGrafo emisor→señal→manejador desde decoradores @receiver
blast_radiusQué afecta una migración destructiva: sus riesgos, el código que aún la lee, el impacto en cascada
driftmakemigrations --check sin iniciar Django — migraciones comparadas contra models.py
impactCada referencia a un campo o nombre de modelo, agrupada por capa de Django
nplusone_scanHallazgos estáticos de N+1 para todo el espacio de trabajo
# Start it directly
django-orm-lens-mcp

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

Resolución del espacio de trabajo (py-1.3.0+). Cada herramienta acepta un argumento opcional workspace_root en la llamada. Prioridad de resolución: argumento explícito → $DJANGO_ORM_LENS_ROOT → directorio de trabajo actual. Rutas inválidas o no-Django devuelven un sobre estructurado ({"error": "WORKSPACE_NOT_DJANGO", "hint": "…"}) en lugar de resultados vacíos, para que el agente pueda autocorregirse. Sandbox opcional mediante DJANGO_ORM_LENS_ALLOWED_ROOTS (separado por ; en Windows, : en otros sistemas).


🛡️ Protege tu CI

Las regresiones de esquema son más baratas de detectar en el momento en que entran a un PR. Cuatro formas sin configuración para bloquearlas:

Bot de PR de radio de impacto — toda la revisión de esquema en un solo comentario, actualizado en el lugar en cada push en lugar de un comentario nuevo 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 }}

El comentario se publica antes de que falle el trabajo, así que un PR bloqueado aún explica por qué. only-changed lee la lista de archivos del PR desde la API en lugar de git diff, porque actions/checkout por defecto es fetch-depth: 1 y el commit base no está en el historial local. En eventos de push ambas banderas se omiten con un aviso en lugar de fallar, así que un solo flujo de trabajo cubre ambos disparadores.

La acción se instala desde PyPI, así que blast-radius y drift necesitan py-1.7.0 o posterior — fíjala con version: 1.7.0 si tu flujo de trabajo no debe desviarse. Para ejecutar una versión no publicada, agrega install: false e instala la fuente tú mismo; el flujo de trabajo de este repositorio hace exactamente eso, y es lo que verifica la acción en cada PR.

pre-commit — dos hooks, nada que 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 — los hallazgos aparecen como anotaciones de PR con cero permisos adicionales:

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

SARIF → Code Scanning — los hallazgos llegan a la pestaña de Seguridad del repositorio:

- 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

Los códigos de salida son nativos de CI: diff y nplusone salen con 1 si hay hallazgos, migration-risk y blast-radius salen con 1 en hallazgos críticos, drift sale con 1 cuando un campo se declara pero nunca se migra. Agrega --exit-zero para el modo solo informe.


🔌 Integraciones

ClienteCómo habilitarloEstado
VS Codecode --install-extension frowningdev.django-orm-lens✅
Cursormismo VSIX + entrada MCP opcional en ~/.cursor/mcp.json✅
Windsurf / VSCodium / cualquier fork de Codeinstala el VSIX desde el Marketplace o GitHub Releases✅
Aideragrega django-orm-lens-mcp a tu mcp.json✅ (vía MCP)
Continue.devregistra el servidor MCP en ~/.continue/config.json✅ (vía MCP)
Zedregistra el servidor MCP en la configuración de Zed✅ (vía MCP)
Cualquier cliente compatible con MCPapunta command a django-orm-lens-mcp, establece DJANGO_ORM_LENS_ROOT✅
pre-commitrepo: https://github.com/FROWNINGdev/django-orm-lens + dos IDs de hook✅
GitHub Actionsuses: FROWNINGdev/django-orm-lens@action-v1 — anotaciones o SARIF✅
Descubrible vía MCP Registrydirectorio oficial de servidores Model Context Protocol✅
Terminal simple / CIpip install django-orm-lens && django-orm-lens scan✅

Ejemplo: Cursor / cualquier cliente MCP

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

⚡ Rendimiento

La suite de regresión analiza los grafos de modelos incluidos de Zulip, Saleor, Wagtail, django CMS y Mezzanine — 59 modelos en 13,478 líneas de models.py real — en aproximadamente 20 ms de extremo a extremo en una laptop (21 ms mejor de 3 en el corpus de fixtures dorados del repositorio; una guardia de <2 s se ejecuta en CI en cada celda de la matriz).

Reprodúcelo tú mismo:

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 quién es esto

  • Desarrolladores de Django que se unen a un código con 10+ aplicaciones y se pierden en el desorden de models.py.
  • Ingenieros freelance / por contrato que necesitan comprender un proyecto Django desconocido en la primera hora, no en la primera semana.
  • Equipos que incorporan nuevos empleados que quieren una vista de esquema de un vistazo sin levantar infraestructura de documentación.
  • Usuarios avanzados de agentes de IA (Cursor / Aider / Zed / Continue / cualquier cliente compatible con MCP) que necesitan que el agente responda preguntas de esquema con precisión — sin darle credenciales de base de datos ni iniciar Django.
  • Pipelines de CI que verifican la forma del esquema (por ejemplo, "¿rompimos accidentalmente un related_name?") sin importar el proyecto.
  • Desarrolladores independientes en solitario con un venv roto o en la laptop de otra persona — sin runserver, sin manage.py migrate, aún funciona.

🗺️ Posición en el mercado

Django ORM Lens se encuentra en la intersección de herramientas de editor y herramientas de agentes de IA — un espacio que ningún paquete existente cubre:

SegmentoOpción existenteQué te cuesta
Iniciar y graficardjango-extensions graph_modelsRequiere Graphviz + configuración de Django + una URL de base de datos funcional
Visor basado en webdjango-schema-graphRequiere un servidor Django en ejecución; aloja una cosa más que puede fallar
Panel de administraciónDjango AdminRequiere runserver + autenticación + base de datos — excelente para datos, no para arquitectura
Plugin de editorEstructura de Django en PyCharmBloqueado a PyCharm; sin CLI, sin historia de agentes de IA
Servidor MCP(ninguno hasta ahora)Los agentes de IA adivinan tu esquema desde el código fuente, de manera imperfecta

Django ORM Lens es la única herramienta que ofrece tres superficies desde un solo analizador: una extensión de VS Code (cualquier fork de Code), una CLI sin dependencias (terminales + CI) y un servidor MCP (agentes de IA). Todo estático. Todo gratuito. Todo MIT.


🤔 ¿En qué se diferencia?

Django ORM Lensdjango-extensions graph_modelsdjango-schema-graphDjango AdminEstructura de Django en PyCharm
Funciona sin un proyecto Django iniciable✅❌❌❌⚠️
Sin instalación (sin graphviz, sin servidor)✅❌❌❌❌ (necesita PyCharm)
Funciona en VS Code / Cursor / cualquier fork de Code✅❌❌❌❌
Árbol lateral dentro del editor✅❌❌❌✅
Diagrama ER en vivo✅✅✅❌❌
Tarjetas flotantes en ForeignKey✅❌❌❌⚠️
CodeLens en clases de modelo✅❌❌❌❌
Soporte de paquete models/ dividido✅⚠️⚠️✅✅
CLI para terminal / CI✅⚠️❌❌❌
Servidor MCP para agentes de IA✅❌❌❌❌
Descubrible en el MCP Registry✅❌❌❌❌
Gratuito y de código abierto (MIT)✅✅✅✅❌ (IDE de pago)
Soporte de versiones de Django4.0 – 5.2última3.2 – 4.1 (obsoleto desde 2023)últimaúltima

django-schema-graph no se ha actualizado desde 2023-05 y no prueba Django 5.x.

Cuando quieres algo más

Límites honestos: perfilado de una solicitud en vivo → django-debug-toolbar. Perfilado histórico de solicitudes → django-silk. Aserciones de recuento de consultas dentro de una suite de pruebas → django-perf-rec. APM de producción en tráfico real → Scout / Sentry. Django ORM Lens deliberadamente se mantiene estático — es la capa que funciona antes de que la aplicación pueda iniciar, y la única que tu CI y tu agente de IA pueden usar en cualquier checkout.


⚙️ Configuración

Los valores predeterminados son opinados y sensatos. Si necesitas ajustar:

// .vscode/settings.json
{
  "djangoOrmLens.excludeGlobs": [
    "**/migrations/**",
    "**/node_modules/**",
    "**/venv/**",
    "**/.venv/**",
    "**/env/**"
  ],
  "djangoOrmLens.autoRefresh": true
}
ConfiguraciónTipoPredeterminadoQué hace
djangoOrmLens.excludeGlobsstring[]Ver arribaPatrones glob para omitir al escanear
djangoOrmLens.autoRefreshbooleantrueReescaneo en cambios de models.py
djangoOrmLens.codeFixes.enabledbooleantrueInterruptor principal para los diagnósticos DOL### + QuickFixes
djangoOrmLens.rulesobject{}Severidad por regla: { "DOL007": "off", "DOL013": "error" }
djangoOrmLens.rulesSelectstring[][]Selección estilo Ruff. ["DOL0"] ejecuta solo reglas de queryset+modelo
djangoOrmLens.rulesIgnorestring[][]Ignorar estilo Ruff. ["DOL03"] silencia reglas de formularios/vistas

🔬 Catálogo de reglas

Dieciocho verificaciones del lado del editor (DOL001–DOL041) con códigos estilo Ruff, severidad por regla y aplicabilidad estilo Clippy — más dieciséis reglas de riesgo de migración del lado de CLI y el analizador estático de N+1. Cada regla ahora tiene su propia página de documentación.

CategoríaReglasEjemplos
QuerysetDOL001–DOL007.count() > 0 → .exists(), acceso a FK en bucles (N+1)
Definición de modeloDOL011–DOL015ForeignKey sin on_delete, null=True en campos de cadena
DatetimeDOL021–DOL022datetime.now() → timezone.now()
Formularios / vistasDOL031–DOL032locals() en render(), Meta.fields = '__all__'
SQL crudoDOL041SET enable_hashjoin = off, plan_cache_mode, jit anulaciones en código de aplicación
Riesgos de migración16 reglasNOT NULL agregado sin valor predeterminado, construcciones de índice con bloqueo de tabla, migraciones de datos irreversibles
N+1 estático1 analizadorAcceso a FK/M2M en bucles sin select_related / prefetch_related

→ Referencia completa de reglas — cada código con ejemplos malos/buenos, comportamiento de QuickFix y sintaxis de supresión.

Suprimir en línea

# 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

La aplicabilidad sigue el Clippy de Rust: las correcciones seguras se pueden aplicar automáticamente ("Corregir todo"), las correcciones de sugerencia se ofrecen como QuickFix pero se revisan, los hallazgos inseguros nunca se aplican automáticamente. Las correcciones están separadas de los analizadores (estilo Roslyn), por lo que una regla puede crecer con múltiples correctores con el tiempo sin tocar la lógica de detección.


🧭 Comandos

Abre la paleta de comandos (Ctrl+Shift+P / Cmd+Shift+P) y escribe "Django ORM Lens":

ComandoQué hace
Django ORM Lens: RefreshForzar un nuevo escaneo del espacio de trabajo
Django ORM Lens: Show ER DiagramAbrir el diagrama ER de Mermaid en paralelo
Django ORM Lens: Filter ModelsFiltrar el árbol por nombre de app / modelo / campo
Django ORM Lens: Clear FilterRestaurar el árbol completo
Django ORM Lens: Jump to ModelProgramático — se activa con clics en el árbol y tarjetas flotantes
Django ORM Lens: Find Reverse ReferencesClic derecho en un modelo — QuickPick de cada FK que apunta a él
Django ORM Lens: Generate factory_boy FactoryClic derecho en un modelo o usar CodeLens — generar un DjangoModelFactory
Django ORM Lens: Schema Diff (Time-Travel)Elegir dos commits — obtener un diff tipado como buffer de markdown
Django ORM Lens: Find Impact (What Uses This?)Clic derecho en un campo o modelo — escaneo de referencias en todo el espacio de trabajo
Django ORM Lens: Build Query (Insert Snippet)Clic derecho en un campo o modelo — elegir una plantilla ORM

🗺️ Hoja de ruta

Publicado

  • Árbol lateral agrupado por app
  • Diagrama ER de Mermaid en vivo
  • Tarjetas flotantes sobre ForeignKey('app.Model')
  • Filtrar árbol por nombre
  • Soporte de paquetes models/ divididos
  • Exportar diagrama ER como SVG
  • CLI de Python + servidor MCP para terminales y agentes de IA
  • Vista de bienvenida para espacios de trabajo vacíos
  • Ir a definición seguro para rutas y markdown flotante saneado
  • v0.3.0 — CodeLens sobre cada clase de modelo (N fields · N relations · Open ER diagram)
  • v0.3.0 — Etiquetas de aristas en el diagrama (CASCADE, SET_NULL, PROTECT, related_name)
  • v0.3.0 — Temas de color con nombre (auto / default / dark / forest / neutral)
  • v0.3.1 — through_model en aristas M2M (contribuido por @kingrubic)
  • v0.3.1 — Listado en el Registro oficial de MCP + Glama.ai
  • v0.6.0 — CLI nplusone — detector estático de N+1 (acceso a FK/M2M dentro de bucles sin select_related/prefetch_related)
  • v0.6.0 — CLI migration-risk — marca operaciones riesgosas en migrations/*.py (15 reglas hoy)
  • v0.6.0 — CLI diff — comparar dos volcados JSON de esquema para revisión de PR
  • v0.6.0 — Minimapa del diagrama ER colorea nodos por app de Django
  • v0.6.0 — Traducciones del README: 🇷🇺 Ruso, 🇪🇸 Español, 🇨🇳 Chino
  • v0.6.0 — Imagen Docker en GHCR: docker run ghcr.io/frowningdev/django-orm-lens
  • v0.7.0 — settings.AUTH_USER_MODEL se resuelve en todas partes: relaciones inversas n+1, remitentes de señales, Mermaid ER, webview de VS Code, panel de relaciones entrantes, ER de React
  • v0.7.0 — Analizador de campos basado en AST: ForeignKey(on_delete=CASCADE, to='User') se resuelve independientemente del orden de kwargs (paridad Python + TS)
  • v0.7.0 — Helpers compartidos públicos: find_user_model, resolve_related_tail, find_model, iter_workspace_py_files (Python) + findUserModel, resolveRelatedTail (TS)
  • v0.7.0 — --verbose ya no recorre el árbol dos veces; WorkspaceIndex.scanned_files lleva el conteo
  • v0.7.3 — Anotaciones de tipo PEP-526 en campos (jti: CharField[str] = models.CharField(...)) ahora se analizan — reportado por @jsabater (#25) con una reproducción limpia de Django Ninja 1.6
  • v0.7.4 — Cabeceras de clase genéricas PEP-695 (Python 3.12+): class Container[T](models.Model): ahora se analiza
  • v0.7.5 — Módulo de modelos con alias (from django.db import models as m) y paquetes de campos de terceros (jsonfield.JSONField) ahora se detectan
  • v0.7.6 — Cuerpos de modelo con sangría de tabulaciones ahora se analizan (los editores que usan tabulaciones por defecto ya no muestran modelos vacíos)
  • v0.8.0 — QuickFixes en línea: 16 reglas (DOL001..DOL032) con severidad por regla + select/ignore estilo Ruff + # django-orm-lens-disable-next-line en línea
  • v0.8.0 — Generador de fábricas: factory_boy a partir de cualquier modelo con proveedores de Faker según el tipo de campo
  • v0.8.0 — Diff de esquema con viaje en el tiempo: elegir dos commits → diff de markdown tipado con detección de renombrados de primera clase
  • v0.8.0 — Análisis de impacto: escaneo de referencias de campos en todo el espacio de trabajo en cada capa de Django con etiquetas de confianza Cierto/Probable/Posible
  • v0.8.0 — Constructor de consultas interactivo: clic derecho → plantilla → fragmento insertado en el cursor, consciente de la gramática (FK obtiene .select_related, related_name respetado)
  • v0.8.0 — Renovación de UX del panel lateral: TreeItem.id estable, tooltips de MarkdownString con enlaces profundos de command:, insignias de FileDecorationProvider, TreeView.badge en la barra de actividad, tres estados de viewsWelcome con compuerta

v1.5.0 — la ola de "un núcleo, tres superficies"

  • Formatos de CI: SARIF 2.1.0 + anotaciones de PR de --format github para nplusone y migration-risk
  • Cuatro analizadores promovidos de solo MCP a la CLI: suggest-indexes, signals, migration-deps, cascade
  • er --format dbml | d2 | plantuml | dot — exportaciones de diagramas estándar de la comunidad (dbdiagram.io, D2, PlantUML, Graphviz — dot contribuido por @JJordan0C)
  • Tres nuevas reglas de riesgo de migración: runpython_no_reverse, alter_unique_together_lock, alter_index_together_deprecated — 15 en total
  • Hooks de pre-commit (django-orm-lens-nplusone, django-orm-lens-migration-risk) + Acción de GitHub compuesta
  • docs/rules/ — una página de documentación para cada regla (19 páginas)
  • Suite de regresión de instantáneas doradas sobre 59 modelos reales (Zulip / Saleor / Wagtail / django CMS / Mezzanine); ruff + mypy ahora controlan el CI
  • Grafo de dependencias de migraciones — migration-deps (texto / json / mermaid)

py-1.7 → 1.8 — la ola de inteligencia de esquema

  • blast-radius — riesgos de migración combinados con lo que aún lee el esquema que tocan, como bot de PR (comment: true, fijo, only-changed)
  • drift — makemigrations --check sin iniciar Django
  • impact <name> — lo que aún referencia un modelo o campo, agrupado por capa de Django
  • blast-radius --stats + stats-sql — conteos de filas de producción opcionales desde SQL de solo lectura que ejecutas tú mismo (la herramienta nunca tiene credenciales de base de datos)
  • nplusone se resuelve entre funciones — un queryset devuelto por un helper se sigue hasta el bucle que lo consume
  • blast_radius, drift y impact expuestos como herramientas MCP — trece herramientas para agentes de IA
  • drift documenta sus marcas de !! / ~ en el informe y en --help — reportado por @sevdog (#57)
  • drift sigue la herencia de bases abstractas — los campos de una base abstracta cuentan como propios del hijo concreto, como los trata Django — reportado por @sevdog (#58)
  • suggest-index reconoce los índices que Django ya creó — clave primaria (pk y id son una sola búsqueda), db_index, unique, claves foráneas, unique_together, UniqueConstraint — reportado por @sevdog (#60), misma causa encontrada independientemente por @RinZ27 (#61)
  • Una sexta fixture dorada — Read the Docs se une a Zulip, Saleor, Wagtail, django-CMS y Mezzanine, poniendo al analizador bajo 75 modelos y 538 campos de Django real — contribuido por @JJordan0C (#62, cerrando #51)
  • TaggableManager de django-taggit se lee como el M2M que es — a través de taggit.TaggedItem a taggit.Tag, through= respetado, tanto en el analizador de Python como en el de TypeScript — contribuido por @Guflly (#63, cerrando #50)
  • DOL021 indica el valor predeterminado de USE_TZ correctamente — False hasta Django 4.2, True desde 5.0, con el USE_TZ = True de la plantilla startproject desde 4.0 señalado como la cosa separada que es — y ya no afirma que timezone.now() siempre es consciente de UTC — encontrado por @Justine0211 mientras traducía la página (#52)
  • La fixture parity_input.py lleva la importación de models que un models.py real tendría — contribuido por @RinZ27 (#64)

py-1.9 → 1.12 — la ola de checkout real

Encontrado ejecutando la CLI sobre checkouts reales de django-oscar, django-guardian, django-allauth y django-cms en lugar de sobre fixtures. Cada uno de estos era invisible para una suite de pruebas verde, y dos de ellos hicieron que la herramienta respondiera con confianza algo falso.

  • Los modelos declarados dentro de un bloque a nivel de módulo se analizan — el modismo de modelo intercambiable (if not is_model_registered(...): y luego un class indentado) que usa todo framework Django conectable, contra el descubrimiento de clases anclado en ^class. django-oscar pasó de 12 modelos, cada uno de su propio directorio tests/, a 82. Las seis instantáneas doradas permanecieron byte-idénticas: una clase en columna 0 se analiza exactamente como antes
  • abstract_models.py se lee junto con models.py — los frameworks conectables mantienen la base abstracta allí y dejan que models.py contenga solo la subclase concreta, así que 72 de los 83 modelos de django-oscar reportaban cero campos entre ellos. Ahora 8, y esos 8 son correctos: subclasifican modelos concretos, donde la herencia de múltiples tablas deja las columnas en la tabla del padre
  • drift ya no falla una compilación por dos directorios de app que comparten nombre — el estado de migración reproducido se fusiona por nombre de app, coincidiendo con cómo ya se clavea el lado declarado. En un checkout real de django-guardian el conteo de bloqueo va de 1 → 0 y la fila duplicada contradictoria desaparece, mientras que un campo genuinamente sin migrar aún bloquea
  • Los modelos de django-mptt ya no son invisibles — MPTTModel es una base reconocida, y TreeForeignKey / TreeOneToOneField / TreeManyToManyField se reportan como los campos de Django que subclasifican, así que TreeForeignKey('self', ...) dibuja exactamente la auto-arista que un ForeignKey('self', ...) simple hace. No se agrega dependencia de django-mptt — el analizador sigue funcionando contra un venv roto. El product.Category de Saleor y su arista de children ahora aparecen en la instantánea dorada: 76 líneas agregadas, ninguna eliminada (cerrando #49)
  • El servidor MCP reporta su propia versión — FastMCP no reenvía ninguna, así que el SDK caía en importlib.metadata.version("mcp") y cada respuesta de initialize nombraba el número de versión del proyecto equivocado al cliente

v0.9 → v0.12.1 — la extensión se pone al día

  • v0.9.0 — Seguimiento parcial de UniqueConstraint en Time-Travel Schema Diff: add / drop / change / rename como eventos tipados, con fromCondition llevando el predicado previo al cambio para que un comentario de revisión pueda mostrar Q(is_primary=True) → Q(is_primary=True, deleted=False), y un renombrado que ya no aparece como un par add + drop con pérdida de información. Múltiples restricciones sin nombre en un mismo modelo se asignan a #anon-<index> en lugar de colapsar en un solo evento. Motivado por django-extensions #1813, donde sqldiff elimina el predicado condition= y los revisores de migraciones nunca ven qué cambió
  • v0.10.0 — La detección de capas del análisis de impacto se ejecuta sobre la ruta relativa al workspace. Antes coincidía con /tests/ y /views.py en cualquier parte de la ruta absoluta de un archivo, por lo que un proyecto clonado en cualquier directorio llamado tests — o un monorepo con services/tests/ por encima — reportaba cada archivo como esa capa, views.py como prueba, admin.py como prueba. También: los mensajes del webview se validan por origen en lugar de por fuente, y se detectan migraciones hoja en conflicto — dos migraciones que reclaman el mismo padre, algo que Django solo reporta en tiempo de migrate
  • v0.10.1 — La ficha de Marketplace menciona análisis de impacto, radio de explosión y deriva de esquema, y dice claramente que la herramienta es gratuita y MIT sin nivel Pro. La página de la tienda aún describía la extensión como un panel lateral y un diagrama ER — lo que era dos versiones antes — así que nadie que buscara esas funciones la encontraba. Los metadatos solo surten efecto al publicar, por eso necesitaba su propio lanzamiento
  • v0.11.0 — La mitad TypeScript del soporte de django-mptt, publicada como lanzamiento propio en lugar de integrarse en uno posterior: entre py-1.12.0 y esta compilación, la CLI y la extensión discrepaban sobre qué contiene un esquema django-mptt, que es exactamente el fallo que el fixture dorado compartido existe para prevenir
  • v0.12.0 — La extensión pide una estrella de GitHub en la tercera apertura iniciada por el usuario del diagrama ER. No al instalar: un aviso que llega antes de que la herramienta haya hecho nada se descarta por reflejo, y ese descarte es permanente en la mente del usuario. Las actualizaciones del panel lateral que re-renderizan un panel ya abierto no cuentan — no son una petición del usuario. "Más tarde" y "No volver a preguntar" se almacenan como estados separados, de modo que un aplazamiento rearma la pregunta exactamente una vez, doce aperturas después; dos avisos es el máximo de por vida. La política es una función pura cubierta por seis pruebas que no necesitan host de VS Code
  • v0.12.1 — Exportar como SVG escribía un archivo ilegible. toSvg devuelve marcado con codificación porcentual donde toPng devuelve base64; la ruta de guardado asumía base64 para cualquier cosa que empezara con data:, y decodificar base64 de texto con codificación porcentual no falla — el decodificador descarta silenciosamente cada carácter fuera de su alfabeto y devuelve bytes. Un documento <svg> de 48 caracteres llegaba al disco con el nombre correcto, un tamaño plausible y ningún contenido válido en ninguna parte. La codificación de transferencia ahora se lee del encabezado de la URL de datos en lugar de adivinarse por el prefijo

Siguiente

  • v0.13.0 — Autocompletado de campos dentro de .filter() / .exclude() / .get() (#3)
  • v0.10.0 — Casillas de alternancia de app / modelo: desmarca una app o modelo en el panel lateral para eliminarlo del diagrama ER
  • Motor de reglas DOL portado a la CLI de Python — un catálogo de reglas, tres superficies

Más adelante

  • Soporte de campos de terceros — django-model-utils (django-taggit incluido en py-1.11.0, django-mptt en py-1.12.0 / v0.11.0)
  • Plugin para JetBrains / PyCharm (si hay demanda)

Vota con 👍 en el issue correspondiente.


❓ Preguntas frecuentes

¿Envías algo de mi código a un servidor?
No. Cada byte permanece en tu máquina. El analizador es TypeScript puro (extensión) o Python puro (CLI). Sin llamadas a LLM, sin telemetría, sin analíticas, sin informes de errores. El renderizador de Mermaid se ejecuta dentro del sandbox del webview de VS Code.
¿Funciona con Poetry / uv / conda / sin venv en absoluto?
Sí. La extensión lee el código fuente de Python directamente — no importa Django y no le importa qué gestor de paquetes uses. La CLI requiere Python 3.9+, pero eso es todo.
Mis modelos están divididos en varios archivos dentro de un paquete models/. ¿Eso funciona?
Sí, desde v0.2.0. Tanto la extensión como la CLI recorren models/*.py junto con el clásico models.py.
¿Puedo usarlo con serializers de DRF, Wagtail, Oscar o modelos base de terceros?
Se detecta cualquier clase que parezca un modelo de Django: subclases de models.Model, bases abstractas que empiecen con Abstract, mixins comunes que terminen en Mixin, y nombres base conocidos como TimeStampedModel o PolymorphicModel. Las clases que no son modelos (ModelAdmin, ModelSerializer, Form, View, Manager, …) se filtran.
¿Qué agentes de IA pueden usar el servidor MCP?
Cualquier cliente compatible con MCP — Cursor, Aider, Continue.dev, Zed y cualquier otra herramienta que hable el protocolo. Solo apunta command al binario instalado django-orm-lens-mcp. Consulta la sección Integrations.
¿Cómo bloqueo regresiones de esquema en CI?
Tres formas, todas de configuración cero: los dos pre-commit hooks, la acción compuesta de GitHub (uses: FROWNINGdev/django-orm-lens@action-v1 con format: github para anotaciones en PR), o --format sarif canalizado a github/codeql-action/upload-sarif para la pestaña de Seguridad. diff / nplusone salen con código 1 si hay hallazgos, migration-risk sale con código 1 si hay hallazgos críticos.
¿Hay una versión para JetBrains / PyCharm?
Todavía no. La ventana de herramientas Django Structure de PyCharm ya es buena, así que el valor añadido es menor. Si suficiente gente lo pide, merece la pena hacerlo.

🆘 Soporte


📜 Licencia

MIT © FROWNINGdev


Hecho para desarrolladores que se preocupan por su código.

Marketplace · PyPI · GitHub · Issues · Discussions · Sponsor