diff --git a/.gitignore b/.gitignore index 01faa45..e12f1a9 100644 --- a/.gitignore +++ b/.gitignore @@ -1,17 +1,6 @@ -*.pyc -# Generische Python-Ignorierungen - -# Kompilierte Python-Dateien -*.pyc -__pycache__/ - -# Virtuelle Umgebungen (häufige Namen) +*.sqlite3 venv/ -env/ -.venv/ - -# Abhängigkeitsdateien (z.B. bei Setuptools/pip) -*.egg-info/ -.eggs/ -dist/ -build/ +__pycache__/ +*.pyc +.DS_Store +db.sqlite3 \ No newline at end of file diff --git a/baseball_organisator/settings.py b/baseball_organisator/settings.py index 73169b9..7822c66 100644 --- a/baseball_organisator/settings.py +++ b/baseball_organisator/settings.py @@ -41,6 +41,7 @@ INSTALLED_APPS = [ 'clubs', 'calendars', 'dashboard', + 'team_stats', ] MIDDLEWARE = [ diff --git a/baseball_organisator/urls.py b/baseball_organisator/urls.py index 5a06906..709fa64 100644 --- a/baseball_organisator/urls.py +++ b/baseball_organisator/urls.py @@ -23,5 +23,6 @@ urlpatterns = [ path('accounts/', include('accounts.urls')), path('clubs/', include('clubs.urls')), path('calendars/', include('calendars.urls')), + path('statistics/', include('team_stats.urls')), path('', include('dashboard.urls')), ] diff --git a/dashboard/templates/dashboard/dashboard.html b/dashboard/templates/dashboard/dashboard.html index 3c6c195..cd21790 100644 --- a/dashboard/templates/dashboard/dashboard.html +++ b/dashboard/templates/dashboard/dashboard.html @@ -6,6 +6,11 @@

Dashboard

+ {% if user.coached_teams.all %} + {% for team in user.coached_teams.all %} + Statistics for {{ team.name }} + {% endfor %} + {% endif %} {% if user.coached_teams.all or user.assisted_teams.all %} Create New Event Player List diff --git a/docs/statiks.md3 b/docs/statiks.md3 new file mode 100644 index 0000000..ce38a4a --- /dev/null +++ b/docs/statiks.md3 @@ -0,0 +1,4 @@ +1. Headline: W-L Record, PCT, und Streak (z.B. "Won 3"). +2. Offense vs Defense: Balkendiagramm RS vs RA. +3. Luck-O-Meter: Vergleich von Real Winning % vs. Pythagorean Winning %. (Fans diskutieren lieben Diskussionen darüber, ob ihr Team "gut" oder nur "glücklich" ist). +4. Inning-Heatmap: Eine Tabelle von Inning 1 bis 9, die zeigt, in welchem Inning das Team die meisten Runs erzielt (z.B. "Wir sind ein 'Late Inning' Team"). diff --git a/team_stats/__init__.py b/team_stats/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/team_stats/admin.py b/team_stats/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/team_stats/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/team_stats/apps.py b/team_stats/apps.py new file mode 100644 index 0000000..49d7554 --- /dev/null +++ b/team_stats/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class TeamStatsConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'team_stats' diff --git a/team_stats/migrations/__init__.py b/team_stats/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/team_stats/models.py b/team_stats/models.py new file mode 100644 index 0000000..71a8362 --- /dev/null +++ b/team_stats/models.py @@ -0,0 +1,3 @@ +from django.db import models + +# Create your models here. diff --git a/team_stats/templates/team_stats/team_statistics.html b/team_stats/templates/team_stats/team_statistics.html new file mode 100644 index 0000000..dcfd738 --- /dev/null +++ b/team_stats/templates/team_stats/team_statistics.html @@ -0,0 +1,70 @@ +{% extends "base.html" %} + +{% block content %} +
+

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 }}
+
+
+
+
+
+ + +
+
+
+
Luck-O-Meter
+
+

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

+

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

+
+
+
+
+
+
Inning Heatmap (Runs Scored)
+
+ + + + {% for inning, runs in inning_runs.items %} + + {% endfor %} + + + + + {% for inning, runs in inning_runs.items %} + + {% endfor %} + + +
{{ inning }}
{{ runs }}
+
+
+
+
+
+{% endblock %} diff --git a/team_stats/tests.py b/team_stats/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/team_stats/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/team_stats/urls.py b/team_stats/urls.py new file mode 100644 index 0000000..e514dab --- /dev/null +++ b/team_stats/urls.py @@ -0,0 +1,8 @@ +from django.urls import path +from . import views + +app_name = 'team_stats' + +urlpatterns = [ + path('team//', views.team_statistics, name='team_statistics'), +] diff --git a/team_stats/views.py b/team_stats/views.py new file mode 100644 index 0000000..00b1b14 --- /dev/null +++ b/team_stats/views.py @@ -0,0 +1,94 @@ +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 + +@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') + + wins = 0 + losses = 0 + runs_scored = 0 + runs_allowed = 0 + inning_runs = {i: 0 for i in range(1, 10)} + streak_counter = 0 + current_streak_type = None + last_game_result = None + + for game in games: + result = game.result + + home_score = sum(result.inning_results.get('home', [])) + away_score = sum(result.inning_results.get('away', [])) + + 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 + + # W-L Record and Streak + 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' + + # Inning Heatmap + team_innings = result.inning_results.get('home' if game.is_home_game else 'away', []) + 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': + streak_str = f"Lost {streak_counter}" + 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 = { + '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, + } + + return render(request, 'team_stats/team_statistics.html', context) \ No newline at end of file