Skip to main content

Static ORM query analyzer for Django — detects N+1, missing indexes, unused queries and more

Project description

django-fox-query 🦊

Static ORM query analyzer for Django. Scans your codebase and detects query performance issues before they hit production.

Installation

pip install django-fox-query

Add to your INSTALLED_APPS:

INSTALLED_APPS = [
    ...
    "django_fox_query",
]

Usage

python manage.py find_query

That's it. No configuration needed, no runtime overhead — it's pure static analysis.

What it detects

N+1 queries

Detects querysets on models that have ForeignKey, OneToOneField or ManyToManyField relations without select_related() or prefetch_related().

# ⚠️ detected
books = Book.objects.all()

# ✅ ok
books = Book.objects.all().select_related('author')

Missing indexes on filter()

Cross-references the fields used in .filter() and .exclude() with the model definition to detect fields without db_index=True or unique=True.

# ⚠️ detected — title has no index
books = Book.objects.filter(title="Django")

Unnecessary field loading

Tracks which fields are actually accessed on a queryset and suggests .values() or .values_list() when only a subset is used.

# ⚠️ detected — only author__name is used
books = Book.objects.all()
for book in books:
    print(book.author.name)

# ✅ suggestion
books = Book.objects.values('author__name')

Unused querysets

Detects querysets assigned to a variable that is never used in the scope.

# 🗑️ detected — authors is never used
authors = Author.objects.filter(name="Victor Hugo")

len() instead of .count()

Detects len(queryset) calls which load all objects into memory instead of issuing a single COUNT query.

# ⚡ detected
count = len(Book.objects.all())

# ✅ suggestion
count = Book.objects.count()

Example output

📄 /app/core/views.py:4
   scope  → my_view
   model  → Book
   method → .objects.all()
   code   → books = Book.objects.all()
   ⚠️  warning → relation 'author' (ForeignKey) → utilise .select_related('author')
   💡 values → seuls 'author__name' sont utilisés → envisage .values('author__name')

📄 /app/core/views.py:5
   scope  → my_view
   model  → Author
   method → .objects.filter()
   code   → authors = Author.objects.filter(name="Victor Hugo")
   🗑️  unused → 'authors' n'est jamais utilisé → query inutile, envisage la suppression
   🔍 filter → filter sur 'name' sans index → ajoute db_index=True sur Author.name

── len() vs count() ──────────────────
📄 /app/core/views.py:12
   code   → count = len(books)
   ⚡ count → len(books) sur un queryset → utilise books.count()

⚠️  3 N+1 potentiel(s) détecté(s)
4 queries trouvées

How it works

find_query parses your Python files using the ast module — no code is executed, no database connection is needed. It builds a map of your ORM calls and your model definitions, then cross-references the two to surface issues.

Migrations and site-packages are automatically ignored.

Requirements

  • Python 3.10+
  • Django 4.0+

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_fox_query-0.1.0.tar.gz (11.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_fox_query-0.1.0-py3-none-any.whl (13.8 kB view details)

Uploaded Python 3

File details

Details for the file django_fox_query-0.1.0.tar.gz.

File metadata

  • Download URL: django_fox_query-0.1.0.tar.gz
  • Upload date:
  • Size: 11.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for django_fox_query-0.1.0.tar.gz
Algorithm Hash digest
SHA256 227329946502ac6a6d5b54c59e9662c713b1e894c90e42dd11a20b5fcaab74ce
MD5 b7df3613e099b10f0c8f2ed4902254de
BLAKE2b-256 34327ddcb47842dabc28860aee11e7911e06ec577562c6d9da56a6881e70b075

See more details on using hashes here.

File details

Details for the file django_fox_query-0.1.0-py3-none-any.whl.

File metadata

File hashes

Hashes for django_fox_query-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 6fc2a4c1061b73ee5cdbaac38673b81e52d93dc75433e145bc0f09036e94c231
MD5 d7d32d124015f13f5715b1af77f18c6e
BLAKE2b-256 8758d200ad19914b4bf9f816239311c7e30d24f1b2ad720494267ea931001e0d

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page