AI code review for Django —
catches the ORM escape-hatch traps.
Django's ORM is safe by default. The bugs happen at the escape hatches: `.raw()` and `.extra()` with f-string interpolation, `mark_safe()` on user input, `DEBUG = True` slipping into prod settings. LGTM's Django hints fire in the bugs + security agents whenever it sees `django` in your requirements or pyproject.
Auto-detected. Zero configuration.
Auto-detected when `django` appears in your `requirements.txt`, `pyproject.toml`, or `Pipfile`. LGTM's Django hint pack loads into the bugs + security + best-practices agents automatically.
Django bugs that hide in plain sight
Four patterns that get past general-purpose code review because they look like idiomatic Django. LGTM knows the shape of each.
ORM escape hatches
`.raw()`, `.extra()`, and `RawSQL()` bypass Django's default parameterization. Team members reach for them when the ORM feels awkward — and f-string a user id into the query. Instant SQL injection on a framework that's normally rock-solid.
mark_safe on user input
Django auto-escapes template variables. `mark_safe()` disables that for the wrapped string. Wrapping user-controlled data in `mark_safe()` is a direct XSS. Easy to write, easy to miss in review.
DEBUG = True in production
Local dev uses `DEBUG = True`. A settings file split (base.py / dev.py / prod.py) is the fix — but until it's set up, one wrong commit ships the debug page + tracebacks to production. Data leakage on every unhandled exception.
Missing CSRF on custom endpoints
Django provides `@csrf_exempt` for cases where a view genuinely can't accept a CSRF token (webhooks, mobile APIs). It's also easy to slap on when tests fail — silently disabling protection on real endpoints.
What LGTM actually catches
Three real examples — the Django-aware bugs + security agents flag these with inline 🎯 Actionable comments and a clear "why" explanation.
def orders_for_user(request):
user_id = request.GET["user_id"]
qs = Order.objects.raw(
f"SELECT * FROM shop_order WHERE user_id = {user_id}"
)
return JsonResponse({"orders": [o.id for o in qs]})What: Django .raw() with f-string interpolation of request.GET data
Why: `request.GET['user_id']` is attacker-controlled. Use parameter binding: `Order.objects.raw('SELECT * FROM shop_order WHERE user_id = %s', [user_id])`.
from django.utils.safestring import mark_safe
def profile_view(request, username):
display = mark_safe(f"Welcome, <b>{username}</b>!")
return render(request, "profile.html", {"display": display})What: mark_safe() wrapping a template string that includes user data
Why: Django's auto-escape is bypassed inside mark_safe. A username of `<script>...</script>` executes in the visitor's browser. Use `format_html` with named placeholders instead — it escapes each interpolation.
# settings.py
DEBUG = True
ALLOWED_HOSTS = ["*"]
SECRET_KEY = "django-insecure-dev-key-1234"What: DEBUG=True + wildcard ALLOWED_HOSTS + hardcoded SECRET_KEY
Why: Any of these in a production-facing settings file is a full-severity issue. Use environment-driven configuration via django-environ, and split settings by env (dev/prod).
Django starter .lgtm.yml
Skip migrations (auto-generated), force the django framework slug, bump SQL / XSS / secret-exposure to critical.
version: 1
paths:
- pattern: "**/migrations/**"
skip: true
- pattern: "**/static/**"
skip: true
frameworks:
- "django"
severity_overrides:
sql-injection: "critical"
xss-reflected: "critical"
sensitive-data-exposure: "critical"
auto_approve_docs_only: true
Commit as .lgtm.yml at your repo root, flip the Enable .lgtm.yml toggle in Repo Settings. Next PR picks it up. See all recipes →
What ships on every Django review
Same pipeline that reviews everything else on LGTM — the Djangohints just tune each agent's attention.
6 agents in parallel
Bugs, Security, Performance, Readability, Best-practices, Documentation. Each with framework-specific hints when LGTM detects your stack.
16 CI/CD detectors
LGTM Security scans your GitHub Actions, Dockerfiles, and lockfiles alongside the code review. Merge-blocking Check Run on block-level findings.
Adversarial verifier
Every finding is refuted by a skeptic LLM before it posts. Only survivors reach your PR. Kills the confident-hallucination class of false positives.
Try LGTM on your Django repo
Free tier: 20 reviews / month, all 6 agents, all 16 security detectors. BYOK OpenAI or Anthropic. No card required.