AI Code Review for Python and Django Projects

AI Code Review for Python and Django Projects

A
Admin Xpiria
September 30, 20266 min read

Django's ORM is friendly enough that it is genuinely easy to forget a real database sits underneath it, right up until a page that worked fine in development takes eight seconds to load with real, production-sized data. Python and Django have their own specific, recognisable set of mistakes, and an AI code reviewer trained on real Django code catches a meaningful share of them before they ever reach a real user.

A diagram showing the specific things an AI reviewer checks in a Python and Django pull request

The N+1 query, Django's version of a very common mistake

Looping over a queryset and accessing a related object inside that loop, `order.customer.name` inside a loop over orders, triggers one separate database query per order instead of one efficient query upfront, unless `select_related` or `prefetch_related` was used beforehand. This is, practically, the single most common real performance bug in Django applications, invisible with ten test records and genuinely painful the moment a real page has a few thousand. An AI reviewer recognises this exact pattern, a relationship accessed inside a loop without the right upfront loading, and flags it well before it reaches real production data.

Mutable default arguments, a genuinely surprising Python trap

Writing a function with `def add_item(item, cart=[]):` looks completely harmless, and is a real, well-documented Python trap, since that empty list is created exactly once, when the function is first defined, and silently shared across every single call that does not explicitly pass its own list in. This produces a genuinely confusing bug where data from one unrelated call mysteriously appears in another. An AI reviewer flags a mutable default argument, a list or dictionary used as a default value, immediately, since this specific pattern is recognisable on sight and rarely intentional.

Raw SQL and the protection Django normally gives you for free

Django's ORM protects against SQL injection automatically, as long as you are genuinely using it as intended. The moment a developer drops into `.raw()` or builds a query with Python string formatting instead of Django's own parameter substitution, that protection is gone. An AI reviewer flags raw query construction that includes a variable directly built into the string rather than passed as a separate, properly escaped parameter, since this exact pattern is one of the most reliably dangerous, and reliably catchable, mistakes in any Django codebase.

CSRF and authentication checks that quietly get skipped

A new view that accepts data without Django's CSRF protection, or without properly checking that a user is actually authorised to see or change the specific object they are requesting, not just logged in generally, is a genuinely serious and genuinely common gap. An AI reviewer checks whether a new endpoint handling a write, a POST, PUT or DELETE, correctly uses Django's protections and checks object-level permissions, not simply whether a user is logged in at all, and flags the views that quietly do not.

Migrations that look fine locally and fail on a real database

A migration that adds a new required field without a default value works perfectly against an empty or freshly seeded local database, and fails, or worse, locks a busy table for a long time, against a real production table already holding a large number of real rows. An AI reviewer checks a new migration for exactly this kind of real-world risk, a required field with no default against an existing table, and flags it before it becomes a real, visible production incident rather than a smooth, unnoticed deploy.

Bare except clauses that quietly swallow real errors

Catching every possible exception with a bare `except:`, or `except Exception:` with no real handling beyond silently passing, means a genuine, serious bug can fail completely silently, leaving no error, no log, nothing to actually alert anyone that something went wrong. An AI reviewer flags overly broad exception handling that does not log or re-raise the real underlying error, since this pattern consistently turns a debuggable problem into a genuinely mysterious one, discovered only once its real consequences show up somewhere else entirely.

What an AI reviewer genuinely will not catch

It will not know that a specific business rule in your own subscription billing logic charges the wrong amount for a particular real combination of plan and discount, since that logic can be entirely valid, well-written Django code and still produce the wrong real-world answer. It will not catch a bug that only appears against your actual production data's specific, unusual shape. And it is not a substitute for a real human who understands why your application is built the way it is, which is exactly why its flagged comments are a genuinely useful first pass, not the final word on whether a pull request is actually ready.

A worked example: what a real review comment looks like

Picture a pull request adding a new admin view that loops through every active subscription and checks each one's related payment history. An AI reviewer's comment might read: "This loop accesses `subscription.payments.all()` inside the loop without prefetching, which will run one query per subscription. Consider `Subscription.objects.prefetch_related('payments')` before the loop." That is a specific, correct, actionable catch, exactly the kind of thing a reviewer focused on whether the report's actual numbers are right could easily read straight past.

Mistakes worth avoiding

Assuming the ORM protects you everywhere by default. It protects you as long as you use it as intended; raw queries and string-built SQL both step outside that protection.

Ignoring an N+1 flag because your local database is small. This specific bug is invisible in development and genuinely painful at real scale, worth fixing the moment it is flagged.

Treating a bare except as a harmless shortcut. It consistently turns a real, debuggable error into a mysterious one discovered far too late.

A short glossary

N+1 query: a performance bug where one query per item in a loop runs instead of one efficient query upfront. select_related / prefetch_related: Django's tools for loading related data upfront, avoiding the N+1 pattern. Mutable default argument: a list or dictionary used as a function's default value, silently shared across calls in a way that surprises most developers the first time they hit it. CSRF: a security flaw where a malicious site tricks a user's browser into making an unwanted request to another site they are logged into.

Where to go from here

Our wider guide to what AI code review actually is covers how these tools work in general, and how they actually detect bugs goes deeper into the underlying mechanics. If your Django project has grown into something a quick read-through can no longer properly cover, our code audit and rescue service is built for a real, thorough, human look.

A
Admin Xpiria
Xpiria Tech Team

Comments

No comments yet. Be the first to share your thoughts.

Leave a comment

Comments are reviewed before they appear. Links are not allowed.

Related Articles