🔧 AI Nachrichten GenAI Workflows für Social Media Content(02.09.2026 um 14:00 Uhr)
🪟 Windows Tipps<b>Windows</b> - IT-Administrator.de(04.09.2026 um 04:17 Uhr)
🔧 AI Nachrichten GenAI Workflows für Social Media Content(02.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenCVE-2026-72643 | Elastic Kibana up to 9.4.4/9.5.0 Agent Builder comparison(05.09.2026 um 14:05 Uhr)
🔧 AI Nachrichten GenAI Workflows für Social Media Content(02.09.2026 um 14:00 Uhr)
🪟 Windows Tipps<b>Windows</b> - IT-Administrator.de(04.09.2026 um 04:17 Uhr)
🔧 AI Nachrichten GenAI Workflows für Social Media Content(02.09.2026 um 14:00 Uhr)
🕵️ SicherheitslückenCVE-2026-72643 | Elastic Kibana up to 9.4.4/9.5.0 Agent Builder comparison(05.09.2026 um 14:05 Uhr)

26 🕛 kürzlich 4 Min Lesezeit
0

How I Caught and Fixed an N+1 Query in My Django REST API

↗ Quelle (dev.to)
🗣️ Stimme:
📑 Inhaltsübersicht

Every performant API eventually runs into the same silent killer: the N+1 query problem. It doesn't crash your app. It doesn't throw errors. It just quietly makes every list endpoint slower as your data grows — and it's almost invisible until Sentry flags it in production.



Today, Sentry caught one on my /api/blog-posts/ endpoint. Here's exactly what happened and how I fixed it in three lines of code.









What Is an N+1 Query?



An N+1 query happens when your code fetches a list of N records, then fires an additional query per record to fetch related data — totalling 1 + N database hits instead of a flat 2 or 3.



In Django, this usually happens silently because the ORM is lazy by default. Accessing a related object on a model instance that wasn't eagerly loaded triggers a fresh SELECT on the spot. With 30 blog posts, that's 30 silent queries you never wrote.









The Offending Code



The BlogPostViewSet looked clean on the surface:




CODE
class BlogPostViewSet(viewsets.ReadOnlyModelViewSet):
queryset = BlogPost.objects.all()
serializer_class = BlogPostSerializer
lookup_field = "uid"






And the serializer:




CODE
class BlogPostSerializer(serializers.ModelSerializer):
tags = BlogTagSerializer(many=True, read_only=True)
series = BlogSeriesSerializer(read_only=True)
...






Spot the problem? BlogPost has two relations:





  • series — a ForeignKey to BlogSeries


  • tags — a ManyToManyField to BlogTag



When DRF serializes a list of 30 posts, it accesses post.series and post.tags on each one. Without eager loading, Django fires two extra queries per post — one to fetch the series, one to fetch the tags. That's 1 + 60 queries for a 30-post list.



The featured action had the same issue:




CODE
@action(detail=False, methods=["get"])
def featured(self, request):
queryset = BlogPost.objects.filter(date_published__isnull=False).order_by(
"-date_published",
)[:3]






A fresh BlogPost.objects call with no eager loading.









The Fix



Django gives me two tools for this:





  • select_related() — for ForeignKey and OneToOne relations. Issues a SQL JOIN and fetches everything in a single query.


  • prefetch_related() — for ManyToMany and reverse FK relations. Issues a second query and caches the results in Python.



The fix:




CODE
class BlogPostViewSet(viewsets.ReadOnlyModelViewSet):
queryset = BlogPost.objects.select_related("series").prefetch_related("tags")
serializer_class = BlogPostSerializer
lookup_field = "uid"

@action(detail=False, methods=["get"])
def featured(self, request):
queryset = (
BlogPost.objects.select_related("series")
.prefetch_related("tags")
.filter(date_published__isnull=False)
.order_by("-date_published")[:3]
)
serializer = self.get_serializer(queryset, many=True)
return Response(serializer.data)






With 30 posts, the list endpoint now costs 3 queries regardless of dataset size:




  1. SELECT * FROM core_blogpost ...

  2. SELECT * FROM core_blogseries WHERE id IN (...)

  3. SELECT * FROM core_blogtag INNER JOIN core_blogpost_tags WHERE blogpost_id IN (...)









The Bonus Fix



While auditing the blog endpoint, I spotted the same pattern in TestimonialViewSet. Its serializer accesses project.title and project.slug, but the queryset had no select_related:




CODE
# Before
queryset = Testimonial.objects.all()

# After
queryset = Testimonial.objects.select_related("project")






One extra line, one less N+1.









How to Spot This in Your Own Code



The pattern is always the same — look for any ViewSet or view where:




  1. The queryset has no select_related or prefetch_related

  2. The serializer accesses a related field (source="relation.field", nested serializers, SerializerMethodField that touches obj.relation)



Tools that help catch this before Sentry does:





  • — raises exceptions in tests when N+1 queries are detected


  • Sentry Performance — catches it in production with query traces



The best time to catch an N+1 is during code review. Any time you write a nested serializer, ask: does the queryset for this view eagerly load this relation?









Takeaway



The Django ORM's lazy evaluation is a feature, not a bug — but it requires discipline at the queryset layer. A clean-looking viewset with objects.all() is often hiding a query storm one serializer away.



The rule of thumb: every relation accessed in a serializer needs a corresponding select_related or prefetch_related on the queryset. Make it a checklist item on every PR that touches a ViewSet.

Vollständiger Original-Bericht
Ausführliche Details, Code-Beispiele & Hersteller-Stellungnahme auf dev.to.
↗ Original-Artikel auf dev.to lesen
Wie bewertest du diesen Beitrag?
1 Klick Feedback
Teilen mit Netzwerk & Team:

Community-Analysen & Experten-Meinungen 0

Verfasse deine eigene Analyse, teile Workarounds oder diskutiere diesen Vorfall im Blog.
Noch keine Community-Analyse verfasst. Markiere einen Textabschnitt oder klicke oben auf Eigene Analyse verfassen“!
Community Pulse: Relevanz-Einschätzung
1 Klick Experten-Votum
🔴 Akute Relevanz 37%
🟡 In Evaluierung 29%
🟢 Keine Auswirkung 16%
Spannende Innovation 18%
Verwandte Story-Cluster & Quellen (Vektor-KI)
Port 8095 Engine
1 Quelle
GenAI Workflows für Social Media Content
1 Quelle
<b>Windows</b> - IT-Administrator.de
1 Quelle
Führt Vibe-Coding und AI-Slop zu <b>Windows</b> 11-Problemen (Desktop-Background, Mauszeiger etc.)?
Ähnliche Beiträge
🔍 Verwandte News

Auch interessante Nachrichten How I Caught and Fixed an N+1 Query in My Django REST API

Thematisch verwandte Begriffe: Caught, Fixed, Query, Django · 6 Treffer

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...

Laden...

Beiträge werden geladen ...

Laden...

Videos werden geladen ...