Optimize GameListView to annotate games with campaign counts, reducing N+1 queries.
This commit is contained in:
parent
fdad881d1e
commit
3ee93d3471
1 changed files with 29 additions and 31 deletions
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
from typing import TYPE_CHECKING, Any
|
from typing import TYPE_CHECKING, Any
|
||||||
|
|
||||||
|
from django.db.models import Count, Q
|
||||||
from django.shortcuts import render
|
from django.shortcuts import render
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from django.views.generic import DetailView, ListView
|
from django.views.generic import DetailView, ListView
|
||||||
|
|
@ -107,41 +108,38 @@ class GameListView(ListView):
|
||||||
context_object_name = "games"
|
context_object_name = "games"
|
||||||
|
|
||||||
def get_queryset(self) -> QuerySet[Game]:
|
def get_queryset(self) -> QuerySet[Game]:
|
||||||
"""Get queryset of games.
|
"""Get queryset of games, annotated with campaign counts to avoid N+1 queries."""
|
||||||
|
now = timezone.now()
|
||||||
Returns:
|
return (
|
||||||
QuerySet: Sorted games.
|
super()
|
||||||
"""
|
.get_queryset()
|
||||||
return super().get_queryset().order_by("display_name")
|
.annotate(
|
||||||
|
campaign_count=Count("drop_campaigns", distinct=True),
|
||||||
|
active_count=Count(
|
||||||
|
"drop_campaigns",
|
||||||
|
filter=Q(
|
||||||
|
drop_campaigns__start_at__lte=now,
|
||||||
|
drop_campaigns__end_at__gte=now,
|
||||||
|
drop_campaigns__status="ACTIVE",
|
||||||
|
),
|
||||||
|
distinct=True,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.order_by("display_name")
|
||||||
|
)
|
||||||
|
|
||||||
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
def get_context_data(self, **kwargs) -> dict[str, Any]:
|
||||||
"""Add additional context data.
|
"""Add additional context data."""
|
||||||
|
|
||||||
Args:
|
|
||||||
**kwargs: Additional arguments.
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: Context data.
|
|
||||||
"""
|
|
||||||
context = super().get_context_data(**kwargs)
|
context = super().get_context_data(**kwargs)
|
||||||
|
# Use annotated counts directly, no extra queries
|
||||||
# Get campaign count for each game
|
context["games_with_counts"] = [
|
||||||
games_with_counts = []
|
{
|
||||||
for game in context["games"]:
|
|
||||||
campaign_count = DropCampaign.objects.filter(game=game).count()
|
|
||||||
active_count = DropCampaign.objects.filter(
|
|
||||||
game=game,
|
|
||||||
start_at__lte=timezone.now(),
|
|
||||||
end_at__gte=timezone.now(),
|
|
||||||
status="ACTIVE",
|
|
||||||
).count()
|
|
||||||
games_with_counts.append({
|
|
||||||
"game": game,
|
"game": game,
|
||||||
"campaign_count": campaign_count,
|
"campaign_count": getattr(game, "campaign_count", 0),
|
||||||
"active_count": active_count,
|
"active_count": getattr(game, "active_count", 0),
|
||||||
})
|
}
|
||||||
|
for game in context["games"]
|
||||||
context["games_with_counts"] = games_with_counts
|
]
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue