from collections import defaultdict from django.views.generic import TemplateView from django.urls import reverse_lazy from django.db.models import Count, Q, Prefetch, Sum, F, IntegerField, Value, BooleanField, Case, When from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger from trades.models import TradeOffer, TradeAcceptance, TradeOfferHaveCard, TradeOfferWantCard from cards.models import Card, CardSet, Rarity from django.utils.decorators import method_decorator from django.views.decorators.cache import cache_page from django.template.response import TemplateResponse from django.http import HttpResponseRedirect @method_decorator(cache_page(60), name='get') class HomePageView(TemplateView): template_name = "home/home.html" def get_base_trade_offer_queryset(self): """ Returns a queryset for TradeOffer that includes prefetches and denormalized aggregates. """ active_states = [ TradeAcceptance.AcceptanceState.ACCEPTED, TradeAcceptance.AcceptanceState.SENT, TradeAcceptance.AcceptanceState.RECEIVED, TradeAcceptance.AcceptanceState.THANKED_BY_INITIATOR, TradeAcceptance.AcceptanceState.THANKED_BY_ACCEPTOR, TradeAcceptance.AcceptanceState.THANKED_BY_BOTH, ] have_cards_prefetch = Prefetch( 'have_cards', queryset=Card.objects.annotate( trade_offer_count=Count("trade_offers_have") ).order_by("trade_offer_count", "id") ) want_cards_prefetch = Prefetch( 'want_cards', queryset=Card.objects.annotate( trade_offer_count=Count("trade_offers_want") ).order_by("trade_offer_count", "id") ) qs = ( TradeOffer.objects.all() .prefetch_related( have_cards_prefetch, "have_cards__decks", "have_cards__rarity", "have_cards__cardset", want_cards_prefetch, "want_cards__decks", "want_cards__rarity", "want_cards__cardset", "acceptances" ) .select_related("initiated_by__user") .annotate( is_active=Case( When( Q(total_have_accepted__lt=F('total_have_quantity')) & Q(total_want_accepted__lt=F('total_want_quantity')), then=Value(True) ), default=Value(False), output_field=BooleanField() ) ) ) return qs def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) # Add available_cards QuerySet so card_multiselect works properly. context["available_cards"] = Card.objects.all() \ .order_by("name", "rarity__pk") \ .select_related("rarity", "cardset") \ .prefetch_related("decks") # Reuse base trade offer queryset for market stats base_offer_qs = self.get_base_trade_offer_queryset().filter(manually_closed=False, is_active=True) # Recent Offers recent_offers_qs = base_offer_qs.order_by("-created_at")[:10] context["recent_offers"] = list(recent_offers_qs)[:5] # Most Offered Cards context["most_offered_cards"] = ( Card.objects.filter(tradeofferhavecard__isnull=False) .annotate(offer_count=Sum("tradeofferhavecard__quantity")) .order_by("-offer_count") .select_related("rarity", "cardset") .prefetch_related("decks")[:5] ) # Most Wanted Cards context["most_wanted_cards"] = ( Card.objects.filter(tradeofferwantcard__isnull=False) .annotate(offer_count=Sum("tradeofferwantcard__quantity")) .order_by("-offer_count") .select_related("rarity", "cardset") .prefetch_related("decks")[:5] ) # Least Offered Cards context["least_offered_cards"] = ( Card.objects.annotate(offer_count=Sum("tradeofferhavecard__quantity")) .order_by("offer_count", "?")[:5] ) # Featured Offers grouped by rarity all_offers = base_offer_qs.order_by("created_at") featured = {} featured["All"] = all_offers[:5] grouped = defaultdict(list) for offer in all_offers: normalized_ids = {card.rarity.normalized_id for card in offer.have_cards.all() if card.rarity} for norm in normalized_ids: grouped[norm].append(offer) norm_ids_available = list(grouped.keys()) rareness_qs = Rarity.objects.filter(pk__in=[6] + [nid for nid in norm_ids_available if nid != 6]) rarity_map = {rarity.pk: rarity.icons for rarity in rareness_qs} for norm in sorted(grouped.keys(), reverse=True): offers = grouped[norm] icon_label = rarity_map.get(norm) if icon_label: featured[icon_label] = offers[:5] context["featured_offers"] = featured return context