← Back to articles

Django · Database Performance

Django N+1 Queries: Choose select_related or prefetch_related

Load related records deliberately to prevent a list endpoint from issuing a query for every row.

A database connects to grouped records through a bundled green pathway beside tangled individual connections.
Batch related records to reduce repeated database queries.

A list page can look correct while quietly issuing repeated database queries. Loading orders once, then reading each order.customer without eager loading, can produce one initial query plus another per order.

Use select_related for single objects
When Order.customer is a ForeignKey, Order.objects.select_related("customer") retrieves the related customer through a SQL join. Accessing order.customer then uses the loaded object. This approach also supports one-to-one relationships.

Use prefetch_related for collections
For a reverse relationship named items, Order.objects.prefetch_related("items") loads related rows separately and associates them in Python. Reading order.items.all() can reuse the prefetched collection.

Combine them intentionally
Order.objects.select_related("customer").prefetch_related("items") suits a screen displaying both customer details and item collections. Fetch only relationships the screen actually uses.

Watch the cache boundary
Calling order.items.filter(active=True) requests a different query and does not reuse the ordinary prefetched all() result. Use a tailored Prefetch when a filtered collection is required.

Measure the complete request
Check query counts while rendering the real response, including serializer and template access. Test several records so growth becomes visible, and consider memory use when prefetching large collections.