Matthias Nagel fb782d85db Feat: Supporter-Team-Statistiken in der Team-Statistikansicht
Erweitert die Team-Statistikansicht um zwei neue Metriken:
- 'Games with Supporters': Zeigt die Anzahl der Spiele an, die mit Unterstützung
  durch ein zweites Team (Supporter-Team) stattgefunden haben.
- 'Avg. Supporter Share': Berechnet den durchschnittlichen Prozentsatz der
  Spieler, die in diesen Spielen vom Supporter-Team gestellt wurden.

Diese Statistiken helfen, den Grad der Abhängigkeit von externer Spielerunterstützung
zu analysieren. Die Anzeige erfolgt in einer neuen Karte auf der Team-Statistikseite.

Änderungen umfassen:
- Anpassung der Funktion  in
  zur Berechnung der neuen Metriken unter Berücksichtigung von
   und .
- Erweiterung des Templates
  um eine neue 'Supporter Stats'-Karte zur Anzeige der berechneten Werte.
2025-11-19 21:14:21 +01:00

150 lines
5.1 KiB
Python

from django.shortcuts import render, get_object_or_404
from django.contrib.auth.decorators import login_required
from django.http import HttpResponseForbidden
from clubs.models import Team
from calendars.models import Game, EventParticipation
def _calculate_statistics(team, season=None):
"""
Calculates statistics for a given team and season.
"""
games_query = Game.objects.filter(team=team, result__isnull=False).prefetch_related('opened_for_teams')
if season:
games_query = games_query.filter(season=season)
games = games_query.order_by('start_time')
wins = 0
losses = 0
runs_scored = 0
runs_allowed = 0
inning_runs = {i: 0 for i in range(1, 10)}
streak_counter = 0
last_game_result = None
games_with_supporters = 0
total_supporter_player_percentage = 0
for game in games:
# Supporter stats
if game.opened_for_teams.exists():
games_with_supporters += 1
attending_players = EventParticipation.objects.filter(event=game, status='attending').select_related('user__team')
total_attendees = attending_players.count()
if total_attendees > 0:
supporter_players_count = attending_players.exclude(user__team=game.team).count()
supporter_percentage = (supporter_players_count / total_attendees) * 100
total_supporter_player_percentage += supporter_percentage
# Standard game stats
result = game.result
sorted_items = sorted(result.inning_results.items(), key=lambda x: int(x[0].split('_')[1]))
home_innings = [
item[1].get('home')
for item in sorted_items
if isinstance(item[1].get('home'), int)
]
away_innings = [
item[1].get('guest')
for item in sorted_items
if isinstance(item[1].get('guest'), int)
]
home_score = sum(home_innings)
away_score = sum(away_innings)
if game.is_home_game:
team_score = home_score
opponent_score = away_score
else:
team_score = away_score
opponent_score = home_score
runs_scored += team_score
runs_allowed += opponent_score
if team_score > opponent_score:
wins += 1
if last_game_result == 'win':
streak_counter += 1
else:
streak_counter = 1
last_game_result = 'win'
elif team_score < opponent_score:
losses += 1
if last_game_result == 'loss':
streak_counter += 1
else:
streak_counter = 1
last_game_result = 'loss'
team_innings = home_innings if game.is_home_game else away_innings
for i, runs in enumerate(team_innings):
if i + 1 in inning_runs:
inning_runs[i + 1] += runs
total_games = wins + losses
pct = (wins / total_games) * 100 if total_games > 0 else 0
if last_game_result == 'win':
streak_str = f"Won {streak_counter}"
elif last_game_result == 'loss':
streak_str = f"Lost {streak_counter}"
else:
streak_str = "N/A"
if runs_scored > 0 or runs_allowed > 0:
pythagorean_pct = (runs_scored**2 / (runs_scored**2 + runs_allowed**2)) * 100
else:
pythagorean_pct = 0
avg_supporter_player_percentage = (total_supporter_player_percentage / games_with_supporters) if games_with_supporters > 0 else 0
return {
'team': team,
'wins': wins,
'losses': losses,
'pct': pct,
'streak': streak_str,
'runs_scored': runs_scored,
'runs_allowed': runs_allowed,
'pythagorean_pct': pythagorean_pct,
'inning_runs': inning_runs,
'total_games': total_games,
'games_with_supporters': games_with_supporters,
'avg_supporter_player_percentage': avg_supporter_player_percentage,
}
@login_required
def team_statistics(request, team_id):
team = get_object_or_404(Team, pk=team_id)
# User must be the head coach of the parent team to view the stats
if request.user != team.head_coach:
return HttpResponseForbidden("You are not authorized to view this page.")
selected_season = request.GET.get('season')
# Create a list of the parent team and all its child teams
teams_to_display = [team] + list(team.child_teams.all())
# Calculate statistics for each team
teams_stats = []
for t in teams_to_display:
stats = _calculate_statistics(t, selected_season)
teams_stats.append(stats)
# Get all available seasons for the filter dropdown
available_seasons = Game.objects.values_list('season', flat=True).distinct().order_by('season')
context = {
'team': team, # Primary team for page header/auth
'teams_stats': teams_stats,
'available_seasons': available_seasons,
'selected_season': selected_season,
}
return render(request, 'team_stats/team_statistics.html', context)