from datetime import date from django.db.models import Prefetch from django.views.generic import DetailView, ListView from apps.scouting.models import FavoritePlayer from apps.stats.models import PlayerSeason from .forms import PlayerSearchForm from .models import Player, PlayerCareerEntry from .services.search import annotate_player_metrics, apply_sorting, base_player_queryset, filter_players def calculate_age(birth_date): if not birth_date: return None today = date.today() return today.year - birth_date.year - ( (today.month, today.day) < (birth_date.month, birth_date.day) ) class PlayerSearchView(ListView): model = Player context_object_name = "players" paginate_by = 20 template_name = "players/index.html" def get_template_names(self): if self.request.headers.get("HX-Request") == "true": return ["players/partials/results.html"] return [self.template_name] def get_form(self): if not hasattr(self, "_search_form"): self._search_form = PlayerSearchForm(self.request.GET) return self._search_form def get_paginate_by(self, queryset): form = self.get_form() if form.is_valid(): return form.cleaned_data.get("page_size") or 20 return self.paginate_by def get_queryset(self): form = self.get_form() form_valid = form.is_valid() if form.is_bound and not form_valid: return Player.objects.none() queryset = base_player_queryset() queryset = filter_players(queryset, form.cleaned_data) queryset = annotate_player_metrics(queryset, form.cleaned_data) queryset = apply_sorting(queryset, form.cleaned_data.get("sort", "name_asc")) return queryset def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) search_form = self.get_form() context["search_form"] = search_form context["search_has_errors"] = search_form.is_bound and bool(search_form.errors) context["favorite_player_ids"] = set() if self.request.user.is_authenticated: player_ids = [player.id for player in context["players"]] context["favorite_player_ids"] = set( FavoritePlayer.objects.filter( user=self.request.user, player_id__in=player_ids, ).values_list("player_id", flat=True) ) return context class PlayerDetailView(DetailView): model = Player template_name = "players/detail.html" context_object_name = "player" def get_queryset(self): season_queryset = PlayerSeason.objects.select_related( "season", "team", "competition", "stats", ).order_by("-season__start_date", "-id") career_queryset = PlayerCareerEntry.objects.select_related( "team", "competition", "season", "role_snapshot", ).order_by("-start_date", "-id") return ( Player.objects.select_related( "nationality", "nominal_position", "inferred_role", "origin_competition", "origin_team", ) .prefetch_related( "aliases", Prefetch("player_seasons", queryset=season_queryset), Prefetch("career_entries", queryset=career_queryset), ) ) def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) player = self.object raw_season_rows = list(player.player_seasons.all()) current_assignment = next( (row for row in raw_season_rows if row.season and row.season.is_current), None, ) if current_assignment is None and raw_season_rows: current_assignment = raw_season_rows[0] season_rows = [] for row in raw_season_rows: try: stats = row.stats except PlayerSeason.stats.RelatedObjectDoesNotExist: stats = None season_rows.append( { "season": row.season, "team": row.team, "competition": row.competition, "games_played": row.games_played, "minutes_played": row.minutes_played, "mpg": (row.minutes_played / row.games_played) if row.games_played else None, "stats": stats, } ) context["age"] = calculate_age(player.birth_date) context["current_assignment"] = current_assignment context["career_entries"] = player.career_entries.all() context["season_rows"] = season_rows context["is_favorite"] = False if self.request.user.is_authenticated: context["is_favorite"] = FavoritePlayer.objects.filter( user=self.request.user, player=player, ).exists() return context