Interview question
Fix a Django N+1 query and protect it with a query-count test
Repairs a Django serialization path with select_related and prefetch_related, then locks the query shape with a regression test.
TL;DR
Repairs a Django serialization path with select_related and prefetch_related, then locks the query shape with a regression test.
Django ORM eager loading, relation shape, serializer access, query counting, representative data, and bounded query cost.
Practice the problem like a real interview: restate, reason, implement, and test.
An order-list endpoint loads 20 orders, then accesses each order's customer and every line's product while serializing. Rewrite the queryset so query count stays constant as the number of orders grows. Add a test that evaluates the complete serialization and proves the bound.
Next in Python Backend Practical Labs: Django inventory reservation
20 orders before repair -> 1 + 20 customer + line/product queries
20 orders after repair -> bounded order/customer + line/product queries
select_related for the single-valued customer relation.prefetch_related for order lines and their products.select_related.lines__product.assertNumQueries.def order_rows():
orders = (
Order.objects
.select_related("customer")
.prefetch_related("lines__product")
.order_by("id")[:20]
)
return [
{
"id": order.id,
"customer": order.customer.name,
"lines": [
{"sku": line.product.sku, "quantity": line.quantity}
for line in order.lines.all()
],
}
for order in orders
]
def test_order_rows_has_bounded_queries(django_assert_num_queries, order_factory):
for _ in range(5):
order_factory(lines=3)
with django_assert_num_queries(3):
rows = order_rows()
assert len(rows) == 5
The database performs a constant number of queries and returns O(orders + lines) rows. Application serialization is O(orders + lines).
select_related for a to-many relation is the wrong loading shape.lines but not lines__product leaves another N+1.Spot a weak answer, missing edge case, or clearer explanation? Send it in.
Say thanks with a standalone, one-time $5 contribution. No account required.