Refactor models
This commit is contained in:
103
core/views.py
103
core/views.py
@ -1,17 +1,17 @@
|
||||
from __future__ import annotations
|
||||
|
||||
import json
|
||||
import logging
|
||||
from collections import defaultdict
|
||||
from typing import TYPE_CHECKING, Any
|
||||
|
||||
from django.db.models import F, Prefetch
|
||||
from django.http import HttpRequest, HttpResponse, JsonResponse
|
||||
from django.db.models import Prefetch
|
||||
from django.http import HttpRequest, HttpResponse
|
||||
from django.shortcuts import render
|
||||
from django.template.response import TemplateResponse
|
||||
from django.utils import timezone
|
||||
from django.views.decorators.http import require_http_methods
|
||||
|
||||
from core.import_json import import_data
|
||||
from core.models import Benefit, DropCampaign, Game, TimeBasedDrop
|
||||
from core.models import DropCampaign, Game, TimeBasedDrop
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from django.db.models.query import QuerySet
|
||||
@ -20,36 +20,6 @@ if TYPE_CHECKING:
|
||||
logger: logging.Logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def get_games_with_drops() -> QuerySet[Game]:
|
||||
"""Get the games with drops, sorted by when the drop campaigns end.
|
||||
|
||||
Returns:
|
||||
QuerySet[Game]: The games with drops.
|
||||
"""
|
||||
# Prefetch the benefits for the time-based drops.
|
||||
benefits_prefetch = Prefetch(lookup="benefits", queryset=Benefit.objects.all())
|
||||
active_time_based_drops: QuerySet[TimeBasedDrop] = TimeBasedDrop.objects.filter(
|
||||
ends_at__gte=timezone.now(),
|
||||
starts_at__lte=timezone.now(),
|
||||
).prefetch_related(benefits_prefetch)
|
||||
|
||||
# Prefetch the active time-based drops for the drop campaigns.
|
||||
drops_prefetch = Prefetch(lookup="drops", queryset=active_time_based_drops)
|
||||
active_campaigns: QuerySet[DropCampaign] = DropCampaign.objects.filter(
|
||||
ends_at__gte=timezone.now(),
|
||||
starts_at__lte=timezone.now(),
|
||||
).prefetch_related(drops_prefetch)
|
||||
|
||||
return (
|
||||
Game.objects.filter(drop_campaigns__in=active_campaigns)
|
||||
.annotate(drop_campaign_end=F("drop_campaigns__ends_at"))
|
||||
.distinct()
|
||||
.prefetch_related(Prefetch("drop_campaigns", queryset=active_campaigns))
|
||||
.select_related("org")
|
||||
.order_by("drop_campaign_end")
|
||||
)
|
||||
|
||||
|
||||
@require_http_methods(request_method_list=["GET", "HEAD"])
|
||||
def get_home(request: HttpRequest) -> HttpResponse:
|
||||
"""Render the index page.
|
||||
@ -60,14 +30,41 @@ def get_home(request: HttpRequest) -> HttpResponse:
|
||||
Returns:
|
||||
HttpResponse: The response object
|
||||
"""
|
||||
try:
|
||||
games: QuerySet[Game] = get_games_with_drops()
|
||||
except Exception:
|
||||
logger.exception("Error fetching reward campaigns or games.")
|
||||
return HttpResponse(status=500)
|
||||
now = timezone.now()
|
||||
grouped_drops = defaultdict(list)
|
||||
|
||||
context: dict[str, Any] = {"games": games}
|
||||
return TemplateResponse(request, "index.html", context)
|
||||
# Query for active drops, efficiently fetching related campaign and game
|
||||
# Also prefetch benefits if you need them in the template
|
||||
current_drops_qs = (
|
||||
TimeBasedDrop.objects.filter(start_at__lte=now, end_at__gte=now)
|
||||
.select_related(
|
||||
"campaign__game", # Follows ForeignKey relationships campaign -> game
|
||||
)
|
||||
.prefetch_related(
|
||||
"benefits", # Efficiently fetches ManyToMany benefits
|
||||
)
|
||||
.order_by(
|
||||
"campaign__game__display_name", # Order by game name first
|
||||
"name", # Then by drop name
|
||||
)
|
||||
)
|
||||
|
||||
# Group the drops by game in Python
|
||||
for drop in current_drops_qs:
|
||||
# Check if the drop has an associated campaign and game
|
||||
if drop.campaign and drop.campaign.game:
|
||||
game = drop.campaign.game
|
||||
grouped_drops[game].append(drop)
|
||||
else:
|
||||
# Handle drops without a game (optional, based on your data integrity)
|
||||
# You could group them under a 'None' key or log a warning
|
||||
# grouped_drops[None].append(drop)
|
||||
pass # Or ignore them
|
||||
|
||||
context = {
|
||||
"grouped_drops": dict(grouped_drops), # Convert defaultdict back to dict for template if preferred
|
||||
}
|
||||
return render(request, "index.html", context)
|
||||
|
||||
|
||||
@require_http_methods(request_method_list=["GET", "HEAD"])
|
||||
@ -117,25 +114,3 @@ def get_games(request: HttpRequest) -> HttpResponse:
|
||||
|
||||
context: dict[str, QuerySet[Game] | str] = {"games": games}
|
||||
return TemplateResponse(request=request, template="games.html", context=context)
|
||||
|
||||
|
||||
@require_http_methods(request_method_list=["POST"])
|
||||
def get_import(request: HttpRequest) -> HttpResponse:
|
||||
"""Import data that are sent from Twitch Drop Miner.
|
||||
|
||||
Args:
|
||||
request (HttpRequest): The request object.
|
||||
|
||||
Returns:
|
||||
HttpResponse: The response object.
|
||||
"""
|
||||
try:
|
||||
data = json.loads(request.body)
|
||||
logger.info(data)
|
||||
|
||||
# Import the data.
|
||||
import_data(data)
|
||||
|
||||
return JsonResponse({"status": "success"}, status=200)
|
||||
except json.JSONDecodeError as e:
|
||||
return JsonResponse({"status": "error", "message": str(e)}, status=400)
|
||||
|
Reference in New Issue
Block a user