Will It Vibe logoWill It Vibe?
DJANGO-015Low severity-4 points

N+1 query smell in a loop over a queryset

Part of Code Quality & Syntax, which counts for 20% of the overall score. When this check fires it deducts 4 points from that category, once per scan, no matter how many places it turns up.

What it detects

A for loop iterates a queryset (Model.objects.all()/.filter(...)) with no select_related/prefetch_related on the iterated expression, and its body calls .objects.get(/.objects.filter( again per iteration. That issues one query per row instead of one query total, which turns a page that should cost a handful of queries into hundreds. Heuristic: cannot see optimization applied on a separately assigned variable a few lines earlier.

Why it matters

A loop over a queryset with no select_related/prefetch_related, whose body issues another .objects.get()/.objects.filter() call per iteration, turns a page that should cost one or two queries into one query per row. On a list of 200 items that is 200+ extra round trips to the database, and it is one of the most common causes of a Django view that is fast in development (a handful of test rows) and slow in production (real data volume).

How to fix it

Add select_related('fk_field') to the queryset for a foreign key or one-to-one relation accessed in the loop (a single SQL JOIN), or prefetch_related('reverse_fk_or_m2m') for a reverse foreign key or many-to-many relation (a second batched query instead of one per row). Then delete the per-iteration .get()/.filter() call the loop no longer needs.

The paid report includes a ready-to-paste prompt for your AI coding agent for every check it finds, pointed at the exact findings from your scan. See pricing

Does your repo trip this check?

Paste a GitHub URL or drop a project folder. Scans run in your browser and take seconds.

Scan your repo

Related Code Quality & Syntax checks