From c63ad532b583280f8bf2cde969829de45456c73c Mon Sep 17 00:00:00 2001 From: Matthias Nagel Date: Wed, 19 Nov 2025 08:43:44 +0100 Subject: [PATCH] =?UTF-8?q?Feat:=20Implementiere=20Team-Statistiken=20f?= =?UTF-8?q?=C3=BCr=20Unterteams=20und=20Saisonauswahl?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Erweitert die Team-Statistikansicht, sodass Head Coaches von übergeordneten Teams auch die Statistiken ihrer untergeordneten Teams einsehen können. Jedes Team wird mit seinen eigenen Statistiken separat dargestellt. Zusätzlich wurde eine Filterfunktion implementiert, die es ermöglicht, die Statistiken nach Saison zu filtern. --- .../templates/team_stats/team_statistics.html | 148 +++++++++++------- team_stats/views.py | 76 +++++---- 2 files changed, 139 insertions(+), 85 deletions(-) diff --git a/team_stats/templates/team_stats/team_statistics.html b/team_stats/templates/team_stats/team_statistics.html index dcfd738..bea42ed 100644 --- a/team_stats/templates/team_stats/team_statistics.html +++ b/team_stats/templates/team_stats/team_statistics.html @@ -4,67 +4,109 @@

Statistics for {{ team.name }}

- -
-
-
-
Record
-
-
{{ wins }} - {{ losses }}
-

PCT: {{ pct|floatformat:3 }}

-

Streak: {{ streak }}

+ +
+
+
+
+ + +
+
+
-
-
-
-
Offense vs Defense
-
-

Runs Scored: {{ runs_scored }}

-

Runs Allowed: {{ runs_allowed }}

-
-
{{ runs_scored }}
-
{{ runs_allowed }}
+ +
+ + {% for stats in teams_stats %} + {% if not forloop.first %} +
+ {% endif %} + +

{{ stats.team.name }}

+ + {% if stats.total_games > 0 %} + +
+
+
+
Record
+
+
{{ stats.wins }} - {{ stats.losses }}
+

PCT: {{ stats.pct|floatformat:3 }}

+

Streak: {{ stats.streak }}

+
+
+
+
+
+
Offense vs Defense
+
+

Runs Scored: {{ stats.runs_scored }}

+

Runs Allowed: {{ stats.runs_allowed }}

+ {% with total_runs=stats.runs_scored|add:stats.runs_allowed %} +
+ {% if total_runs > 0 %} +
{{ stats.runs_scored }}
+
{{ stats.runs_allowed }}
+ {% else %} +
0
+ {% endif %} +
+ {% endwith %} +
-
-
- -
-
-
-
Luck-O-Meter
-
-

Real Winning %: {{ pct|floatformat:3 }}

-

Pythagorean Winning %: {{ pythagorean_pct|floatformat:3 }}

+ +
+
+
+
Luck-O-Meter
+
+

Real Winning %: {{ stats.pct|floatformat:3 }}

+

Pythagorean Winning %: {{ stats.pythagorean_pct|floatformat:3 }}

+
+
+
+
+
+
Inning Heatmap (Runs Scored)
+
+ + + + {% for inning, runs in stats.inning_runs.items %} + + {% endfor %} + + + + + {% for inning, runs in stats.inning_runs.items %} + + {% endfor %} + + +
{{ inning }}
{{ runs }}
+
+
-
-
-
-
Inning Heatmap (Runs Scored)
-
- - - - {% for inning, runs in inning_runs.items %} - - {% endfor %} - - - - - {% for inning, runs in inning_runs.items %} - - {% endfor %} - - -
{{ inning }}
{{ runs }}
-
+ {% else %} + -
-
+ {% endif %} + {% endfor %}
{% endblock %} diff --git a/team_stats/views.py b/team_stats/views.py index b7d967a..9e84019 100644 --- a/team_stats/views.py +++ b/team_stats/views.py @@ -2,17 +2,17 @@ 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, GameResult +from calendars.models import Game -@login_required -def team_statistics(request, team_id): - team = get_object_or_404(Team, pk=team_id) - - # Check if the user is the head coach of the team - if request.user != team.head_coach: - return HttpResponseForbidden("You are not authorized to view this page.") - - games = Game.objects.filter(team=team, result__isnull=False).order_by('start_time') +def _calculate_statistics(team, season=None): + """ + Calculates statistics for a given team and season. + """ + games_query = Game.objects.filter(team=team, result__isnull=False) + if season: + games_query = games_query.filter(season=season) + + games = games_query.order_by('start_time') wins = 0 losses = 0 @@ -25,16 +25,13 @@ def team_statistics(request, team_id): for game in games: result = game.result - print("DEBUGGER:"+str(result)) - print("INNING_RESULTS:"+str(result.inning_results)) - sorted_items = sorted(result.inning_results.items(),key=lambda x: int(x[0].split('_')[1])) + 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) ] - sorted_items = sorted(result.inning_results.items(),key=lambda x: int(x[0].split('_')[1])) away_innings = [ item[1].get('guest') for item in sorted_items @@ -42,25 +39,17 @@ def team_statistics(request, team_id): ] home_score = sum(home_innings) away_score = sum(away_innings) - print("HOMEINNING:"+str(home_innings)) + if game.is_home_game: - print("HEIMSPIEL") team_score = home_score opponent_score = away_score - print("Teamscore"+str(team_score)) - print("Gegnerscore"+str(opponent_score)) else: - print("Auswerts") team_score = away_score opponent_score = home_score - print("Teamscore"+str(team_score)) - print("Gegnerscore"+str(opponent_score)) runs_scored += team_score runs_allowed += opponent_score - - # W-L Record and Streak if team_score > opponent_score: wins += 1 if last_game_result == 'win': @@ -75,19 +64,15 @@ def team_statistics(request, team_id): else: streak_counter = 1 last_game_result = 'loss' - print("Win:"+str(wins)) - print("Looses:"+str(losses)) - # Inning Heatmap + 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 - # Winning Percentage (PCT) total_games = wins + losses pct = (wins / total_games) * 100 if total_games > 0 else 0 - # Streak if last_game_result == 'win': streak_str = f"Won {streak_counter}" elif last_game_result == 'loss': @@ -95,14 +80,12 @@ def team_statistics(request, team_id): else: streak_str = "N/A" - # Pythagorean Winning Percentage if runs_scored > 0 or runs_allowed > 0: pythagorean_pct = (runs_scored**2 / (runs_scored**2 + runs_allowed**2)) * 100 else: pythagorean_pct = 0 - - context = { + return { 'team': team, 'wins': wins, 'losses': losses, @@ -112,7 +95,36 @@ def team_statistics(request, team_id): 'runs_allowed': runs_allowed, 'pythagorean_pct': pythagorean_pct, 'inning_runs': inning_runs, + 'total_games': total_games, + } + +@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, } - print("DebuggeR:"+str(context)) return render(request, 'team_stats/team_statistics.html', context)