feat: general improvements, show wins, losses, draws (broken for clubs)

This commit is contained in:
2025-06-15 04:47:24 +02:00
parent fc1e636cfd
commit 8bc1dcb876
6 changed files with 224 additions and 56 deletions

View File

@@ -139,7 +139,7 @@ def get_matches(r = None, id_zawodnika: str | None = None, rok: int | None = Non
# GET /api/v1/player_stats # GET /api/v1/player_stats
def player_stats(r = None, id_zawodnika: str | None = None): def player_stats(r = None, id_zawodnika: str | None = None):
""" """
Zwraca mecze. Zwraca statystyki gracza.
Przykład wywołania: Przykład wywołania:
player_stats(r, id_zawodnika=1), tożsame z GET /api/v1/player_stats?id_zawodnika=1 player_stats(r, id_zawodnika=1), tożsame z GET /api/v1/player_stats?id_zawodnika=1
player_stats(r), tożsame z GET /api/v1/player_stats player_stats(r), tożsame z GET /api/v1/player_stats
@@ -151,11 +151,10 @@ def player_stats(r = None, id_zawodnika: str | None = None):
id_zawodnika = r.args.get('id_zawodnika', 0) id_zawodnika = r.args.get('id_zawodnika', 0)
# Sprawdź, czy sportowiec o podanym (lub niepodanym) id istnieje. # Sprawdź, czy sportowiec o podanym (lub niepodanym) id istnieje.
# Jeśli nie istnieje, wypisz wszystkie mecze.
elif not czy_sportowiec_istnieje(id_zawodnika=id_zawodnika): elif not czy_sportowiec_istnieje(id_zawodnika=id_zawodnika):
return 404, "error", {"error_msg": "This sportsman has not been found in the database. Try: id_zawodnika=1"} return 404, "error", {"error_msg": "This sportsman has not been found in the database. Try: id_zawodnika=1"}
# Gdy sportowiec istnieje, wypisz jego mecze. # Gdy sportowiec istnieje, wypisz jego statystyki.
else: else:
staty = getDb().get_basic_stats(id_zawodnika=id_zawodnika) staty = getDb().get_basic_stats(id_zawodnika=id_zawodnika)
@@ -168,6 +167,9 @@ def player_stats(r = None, id_zawodnika: str | None = None):
'yellow_cards': staty[4], 'yellow_cards': staty[4],
'red_cards': staty[5], 'red_cards': staty[5],
'avg_score': staty[6], 'avg_score': staty[6],
'wins': staty[7],
'draws': staty[8],
'losses': staty[9]
} }
) )
print(f"zwracam staty: {response_json}") print(f"zwracam staty: {response_json}")
@@ -176,27 +178,26 @@ def player_stats(r = None, id_zawodnika: str | None = None):
# GET /api/v1/robert_stats # GET /api/v1/robert_stats
def robert_stats(r = None, id_klubu: str | None = None): def robert_stats(r = None, id_klubu: str | None = None):
""" """
Zwraca mecze. Zwraca statystyki Roberta w danym klubie.
Przykład wywołania: Przykład wywołania:
robert_stats(r, id_zawodnika=1), tożsame z GET /api/v1/robert_stats?id_klubu=barcelona robert_stats(r, id_klubu="barcelona"), tożsame z GET /api/v1/robert_stats?id_klubu=barcelona
robert_stats(r), tożsame z GET /api/v1/robert_stats
""" """
response_json = [] response_json = []
if id_klubu is None: if id_klubu is None:
# Gdy nie podano id wprost, sprawdź, czy podano je przez parametr. # Gdy nie podano id wprost, sprawdź, czy podano je przez parametr.
id_klubu = r.args.get('id_klubu', 0) id_klubu = r.args.get('id_klubu', "non-existent-club-id")
# Sprawdź, czy sportowiec o podanym (lub niepodanym) id istnieje. # Sprawdź, czy klub o podanym (lub niepodanym) id istnieje.
# Jeśli nie istnieje, wypisz wszystkie mecze. if not czy_klub_istnieje(id_klubu=id_klubu):
elif not czy_klub_istnieje(id_klubu=id_klubu):
return 404, "error", {"error_msg": "This club has not been found in the database. Try: id_klubu=barcelona"} return 404, "error", {"error_msg": "This club has not been found in the database. Try: id_klubu=barcelona"}
# Gdy sportowiec istnieje, wypisz jego mecze. # Gdy klub istnieje, wypisz statystyki z tego klubu.
else: else:
staty = getDb().get_sportsman_club_stats(id_zawodnika=1, id_klubu=id_klubu) staty = getDb().get_sportsman_club_stats(id_zawodnika=1, id_klubu=id_klubu)
# for stat in staty: # for stat in staty:
print(staty)
response_json.append({ response_json.append({
'unique_items': staty[0], 'unique_items': staty[0],
'time_played': staty[1], 'time_played': staty[1],
@@ -205,11 +206,46 @@ def robert_stats(r = None, id_klubu: str | None = None):
'yellow_cards': staty[4], 'yellow_cards': staty[4],
'red_cards': staty[5], 'red_cards': staty[5],
'avg_score': staty[6], 'avg_score': staty[6],
'wins': staty[7],
'draws': staty[8],
'losses': staty[9]
} }
) )
print(f"zwracam staty roberta: {response_json}") print(f"zwracam staty roberta: {response_json}")
return 200, "ok", response_json return 200, "ok", response_json
# GET /api/v1/clubs
def clubs(r, id_klubu: str = None):
"""
Zwraca informacje o klubach.
Przykład wywołania:
clubs(r, id_klubu="barcelona"), tożsame z GET /api/v1/clubs?id_klubu=barcelona
clubs(r), tożsame z GET /api/v1/clubs
"""
response_json = []
if id_klubu is None:
# Gdy nie podano id wprost, sprawdź, czy podano je przez parametr.
id_klubu = r.args.get('id_klubu', -1)
if id_klubu == -1:
kluby = getDb().simple_select_all("kluby")
# Sprawdź, czy sportowiec o podanym (lub niepodanym) id istnieje.
# Jeśli nie istnieje, wypisz wszystkie mecze.
elif not czy_klub_istnieje(id_klubu=id_klubu):
return 404, "error", {"error_msg": "This club has not been found in the database. Try: id_klubu=barcelona"}
# Gdy sportowiec istnieje, wypisz jego mecze.
else:
kluby = getDb().simple_select_all("kluby", id_klubu=id_klubu)
for klub in kluby:
response_json.append(klub.jsonify())
print(f"zwracam kluby: {response_json}")
return 200, "ok", response_json
# GET /api/v1/debugger_halt?token=XXX... # GET /api/v1/debugger_halt?token=XXX...
@require_authentication @require_authentication
def debugger_halt(r): def debugger_halt(r):
@@ -266,6 +302,8 @@ def lookup(data, request):
return player_stats(r = request) return player_stats(r = request)
case 'robert_stats': case 'robert_stats':
return robert_stats(r = request) return robert_stats(r = request)
case 'clubs':
return clubs(r = request)
case _: case _:
increment_bad_requests() increment_bad_requests()
return not_implemented(data) return not_implemented(data)

View File

@@ -1,7 +1,7 @@
from datetime import datetime from datetime import datetime
from flask_sqlalchemy import SQLAlchemy from flask_sqlalchemy import SQLAlchemy
from functools import wraps from functools import wraps
from sqlalchemy import ForeignKey, select, insert, update, extract, func from sqlalchemy import ForeignKey, select, insert, update, extract, func, case, literal_column
from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase, Session, relationship from sqlalchemy.orm import Mapped, mapped_column, DeclarativeBase, Session, relationship
from typing import List from typing import List
import time import time
@@ -145,6 +145,13 @@ class baza():
def __repr__(self): def __repr__(self):
return f"<Klub #{self.id_klubu} ({self.skrocona_nazwa})>" return f"<Klub #{self.id_klubu} ({self.skrocona_nazwa})>"
def jsonify(self):
return {
"id_klubu": self.id_klubu,
"pelna_nazwa": self.pelna_nazwa,
"skrocona_nazwa": self.skrocona_nazwa
}
class mecze(Base): class mecze(Base):
__tablename__ = tnp + "mecze" __tablename__ = tnp + "mecze"
id_meczu: Mapped[ int] = mapped_column(primary_key=True, autoincrement=True) id_meczu: Mapped[ int] = mapped_column(primary_key=True, autoincrement=True)
@@ -568,6 +575,10 @@ class baza():
# Aliasy # Aliasy
SportowcyWMeczach = self.entities["sportowcy_w_meczach"] SportowcyWMeczach = self.entities["sportowcy_w_meczach"]
# Zlicz liczbę zwycięstw, remisów i przegranych.
# https://stackoverflow.com/a/3975328
# https://stackoverflow.com/a/49064561
# Czy da się to zrobić prościej? Nie wiem. ~ sherl
query = self.session.query( query = self.session.query(
func.count(SportowcyWMeczach.id_rekordu ).label('unique_items'), func.count(SportowcyWMeczach.id_rekordu ).label('unique_items'),
func.sum( SportowcyWMeczach.czas_gry ).label('time_played'), func.sum( SportowcyWMeczach.czas_gry ).label('time_played'),
@@ -576,6 +587,31 @@ class baza():
func.sum( SportowcyWMeczach.zolte_kartki ).label('yellow_cards'), func.sum( SportowcyWMeczach.zolte_kartki ).label('yellow_cards'),
func.sum( SportowcyWMeczach.czerwone_kartki).label('red_cards'), func.sum( SportowcyWMeczach.czerwone_kartki).label('red_cards'),
func.avg( SportowcyWMeczach.wynik ).label('avg_score'), func.avg( SportowcyWMeczach.wynik ).label('avg_score'),
# Kompatybilne z każdą bazą.
# https://docs.sqlalchemy.org/en/20/core/sqlelement.html#sqlalchemy.sql.expression.case
# https://modern-sql.com/feature/filter
func.sum(
case(
(SportowcyWMeczach.wygrana == 1, 1),
else_ = 0
)
).label('wins'),
func.sum(
case(
(SportowcyWMeczach.wygrana == 0, 1),
else_ = 0
)
).label('draws'),
func.sum(
case(
(SportowcyWMeczach.wygrana == -1, 1),
else_ = 0
)
).label('losses'),
).where( ).where(
SportowcyWMeczach.czas_gry > 0 SportowcyWMeczach.czas_gry > 0
).where( ).where(
@@ -603,6 +639,10 @@ class baza():
# Aliasy # Aliasy
SportowcyWMeczach = self.entities["sportowcy_w_meczach"] SportowcyWMeczach = self.entities["sportowcy_w_meczach"]
# Zlicz liczbę zwycięstw, remisów i przegranych.
# https://stackoverflow.com/a/3975328
# https://stackoverflow.com/a/49064561
# Czy da się to zrobić prościej? Nie wiem. ~ sherl
query = self.session.query( query = self.session.query(
func.count(SportowcyWMeczach.id_rekordu ).label('unique_items'), func.count(SportowcyWMeczach.id_rekordu ).label('unique_items'),
func.sum( SportowcyWMeczach.czas_gry ).label('time_played'), func.sum( SportowcyWMeczach.czas_gry ).label('time_played'),
@@ -611,6 +651,34 @@ class baza():
func.sum( SportowcyWMeczach.zolte_kartki ).label('yellow_cards'), func.sum( SportowcyWMeczach.zolte_kartki ).label('yellow_cards'),
func.sum( SportowcyWMeczach.czerwone_kartki).label('red_cards'), func.sum( SportowcyWMeczach.czerwone_kartki).label('red_cards'),
func.avg( SportowcyWMeczach.wynik ).label('avg_score'), func.avg( SportowcyWMeczach.wynik ).label('avg_score'),
# Kompatybilne z każdą bazą.
# https://docs.sqlalchemy.org/en/20/core/sqlelement.html#sqlalchemy.sql.expression.case
# https://modern-sql.com/feature/filter
func.sum(
case(
(SportowcyWMeczach.wygrana == 1, 1),
else_ = 0
)
).label('wins'),
# UWAGA! Jeśli jest remis, to nie wiemy dla którego klubu grał sportowiec!
# Poniższe wyrażenie jest poprawne, to dane zwracane przez flashscore są
# niewystarczające, aby stwierdzić w którym klubie grał sportowiec!
func.sum(
case(
(SportowcyWMeczach.wygrana == 0, 1),
else_ = 0
)
).label('draws'),
func.sum(
case(
(SportowcyWMeczach.wygrana == -1, 1),
else_ = 0
)
).label('losses'),
).where( ).where(
SportowcyWMeczach.czas_gry > 0 SportowcyWMeczach.czas_gry > 0
).where( ).where(

View File

@@ -3,7 +3,7 @@ import lewy_api_v1
import lewy_db import lewy_db
import lewy_globals import lewy_globals
import json import json
from lewy_api_v1 import get_matches, player_stats, robert_stats from lewy_api_v1 import get_matches, player_stats, robert_stats, clubs as get_clubs
def get_lewy_stats(): def get_lewy_stats():
stats = player_stats(id_zawodnika=1)[2][0] stats = player_stats(id_zawodnika=1)[2][0]
polska = robert_stats(id_klubu="polska")[2][0] polska = robert_stats(id_klubu="polska")[2][0]
@@ -37,6 +37,11 @@ def get_lewy_stats():
'cards': { 'cards': {
'yellow': stats["yellow_cards"], # 86 'yellow': stats["yellow_cards"], # 86
'red': stats["red_cards"], # 2 'red': stats["red_cards"], # 2
},
'wins_losses': {
'wins': stats["wins"],
'draws': stats["draws"],
'losses': stats["losses"]
} }
} }
@@ -78,28 +83,68 @@ def statystyki():
return render_template('stats.html', **dane) return render_template('stats.html', **dane)
def clubs(): def clubs():
selected_club = request.args.get("club","FC Barcelona") selected_club = request.args.get("club", "barcelona")
clubs = [ #clubs = [
{'club': 'FC Barcelona', 'goals': 101,'assist':20, 'matches':147,'minutes_played': 11684,'yellow_card':12,'red_card': 1, 'wins':101, 'draws': 14,'lost': 32}, # {'club': 'FC Barcelona', 'goals': 101,'assist':20, 'matches':147,'minutes_played': 11684,'yellow_card':12,'red_card': 1, 'wins':101, 'draws': 14,'lost': 32},
{'club': 'Bayern Monachium', 'goals': 344,'assist':73,'matches':375,'minutes_played': 31759,'yellow_card':36,'red_card': 0, 'wins':307, 'draws': 35,'lost': 33}, # {'club': 'Bayern Monachium', 'goals': 344,'assist':73,'matches':375,'minutes_played': 31759,'yellow_card':36,'red_card': 0, 'wins':307, 'draws': 35,'lost': 33},
{'club': 'Borussia Dortmund', 'goals': 103,'assist':42,'matches':187,'minutes_played': 14374,'yellow_card':19,'red_card': 1, 'wins':120, 'draws': 40,'lost': 27}, # {'club': 'Borussia Dortmund', 'goals': 103,'assist':42,'matches':187,'minutes_played': 14374,'yellow_card':19,'red_card': 1, 'wins':120, 'draws': 40,'lost': 27},
{'club': 'Lech Poznan', 'goals': 41,'assist':19,'matches':82,'minutes_played': 6858,'yellow_card':9,'red_card': 0, 'wins':'-', 'draws': '-','lost': '-'}, # {'club': 'Lech Poznan', 'goals': 41,'assist':19,'matches':82,'minutes_played': 6858,'yellow_card':9,'red_card': 0, 'wins':'-', 'draws': '-','lost': '-'},
] #]
return render_template('club.html', clubs=clubs, selected_club=selected_club) response_json = {
"club": "Błędny klub",
"goals": 0,
"assist": 0,
"matches": 0,
"minutes_played": 0,
"yellow_card": 0,
"red_card": 0,
"wins": 0,
"draws": 0,
"lost": 0
}
club = get_clubs(request, id_klubu=selected_club)
if club[1] == "ok": # gdy nie wystąpił bład, bo jest taki klub
club = club[2][0]
staty = robert_stats(id_klubu=club["id_klubu"])[2][0]
response_json["club"] = club["pelna_nazwa"]
response_json["goals"] = staty["goals"]
response_json["assist"] = staty["assists"]
response_json["matches"] = staty["unique_items"]
response_json["minutes_played"] = staty["time_played"]
response_json["yellow_card"] = staty["yellow_cards"]
response_json["red_card"] = staty["red_cards"]
response_json["wins"] = staty["wins"]
response_json["draws"] = staty["draws"]
response_json["lost"] = staty["losses"]
return render_template('club.html', clubs=clubs, selected_club=selected_club, resp_json=response_json)
def representation(): def representation():
nation_stats = { # nation_stats = {
'goals': 85, # 'goals': 85,
'assists': 35, # 'assists': 35,
'matches': 158, # 'matches': 158,
'minutes_played': 12108, # 'minutes_played': 12108,
'yellow_card':10, # 'yellow_card':10,
'red_card': 0, # 'red_card': 0,
'wins':75, # 'wins':75,
'draws': 35, # 'draws': 35,
'lost': 48 # 'lost': 48
} # }
return render_template('representation.html', nation_stats=nation_stats) response_json = {}
staty = robert_stats(id_klubu="polska")[2][0]
response_json["goals"] = staty["goals"]
response_json["assist"] = staty["assists"]
response_json["matches"] = staty["unique_items"]
response_json["minutes_played"] = staty["time_played"]
response_json["yellow_card"] = staty["yellow_cards"]
response_json["red_card"] = staty["red_cards"]
response_json["wins"] = staty["wins"]
response_json["draws"] = staty["draws"]
response_json["lost"] = staty["losses"]
return render_template('representation.html', nation_stats=response_json)
def compare(): def compare():
selected_player = request.args.get("player","Leo Messi") selected_player = request.args.get("player","Leo Messi")
lewy=get_lewy_stats() lewy=get_lewy_stats()

View File

@@ -4,59 +4,59 @@
{% block content %} {% block content %}
<section class="choose-club"> <section class="choose-club">
<a href="{{ url_for('clubs', club='FC Barcelona') }}"> <a href="{{ url_for('clubs', club='barcelona') }}">
<button><img src="{{ url_for('static', filename='FC_Barcelona.png') }}"></button> <button><img src="{{ url_for('static', filename='FC_Barcelona.png') }}"></button>
</a> </a>
<a href="{{ url_for('clubs', club='Bayern Monachium') }}"> <a href="{{ url_for('clubs', club='bayern') }}">
<button><img src="{{ url_for('static', filename='FC_Bayern.png') }}"></button> <button><img src="{{ url_for('static', filename='FC_Bayern.png') }}"></button>
</a> </a>
<a href="{{ url_for('clubs', club='Borussia Dortmund') }}"> <a href="{{ url_for('clubs', club='dortmund') }}">
<button><img src="{{ url_for('static', filename='Borussia_Dortmund.png') }}"></button> <button><img src="{{ url_for('static', filename='Borussia_Dortmund.png') }}"></button>
</a> </a>
<!--Jak nie będzie statysytk dla lecha to usunać--> <!--Jak nie będzie statysytk dla lecha to usunać-->
<a href="{{ url_for('clubs', club='Lech Poznan') }}"> <!-- <a href="{{ url_for('clubs', club='Lech Poznan') }}">
<button><img src="{{ url_for('static', filename='Lech_Poznan.png') }}"></button> <button><img src="{{ url_for('static', filename='Lech_Poznan.png') }}"></button>
</a> </a> -->
</section> </section>
<!-- Wyświetlanie danych tylko dla wybranego klubu --> <!-- Wyświetlanie danych tylko dla wybranego klubu -->
{% for stats in clubs %} {#{% for stats in clubs %}#}
{% if stats.club == selected_club %} {#{% if stats.club == selected_club %}#}
<section class="club-stats"> <section class="club-stats">
<h2>Statystyki dla {{selected_club}}</h2> <h2>Statystyki dla {{resp_json.club}}</h2>
<div class="wybrany{{selected_club}}"></div> <div class="wybrany{{resp_json.club}}"></div>
<div class="club-stats-grid"> <div class="club-stats-grid">
<div class="stat-box"> <div class="stat-box">
<p>Gole:</p> <span class="stat-box-special"> {{ stats.goals }} </span> <p>Gole:</p> <span class="stat-box-special"> {{ resp_json.goals }} </span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Asysty:</p> <span class="stat-box-special"> {{ stats.assist }} </span> <p>Asysty:</p> <span class="stat-box-special"> {{ resp_json.assist }} </span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Występy:</p> <span class="stat-box-special"> {{ stats.matches }} </span> <p>Występy:</p> <span class="stat-box-special"> {{ resp_json.matches }} </span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Łączny czas gry:</p> <span class="stat-box-special"> {{ stats.minutes_played }}</span> <p>Łączny czas gry:</p> <span class="stat-box-special"> {{ resp_json.minutes_played }}</span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Żółte kartki:</p> <span class="stat-box-special"> {{ stats.yellow_card }}</span> <p>Żółte kartki:</p> <span class="stat-box-special"> {{ resp_json.yellow_card }}</span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Czerwone kartki:</p> <span class="stat-box-special"> {{ stats.red_card }}</span> <p>Czerwone kartki:</p> <span class="stat-box-special"> {{ resp_json.red_card }}</span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Zwycięstwa:</p> <span class="stat-box-special"> {{ stats.wins }}</span> <p>Zwycięstwa:</p> <span class="stat-box-special"> {{ resp_json.wins }}</span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Remisy:</p> <span class="stat-box-special"> {{ stats.draws }}</span> <p>Remisy:</p> <span class="stat-box-special"> {{ resp_json.draws }}</span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Porażki:</p> <span class="stat-box-special"> {{ stats.lost }}</span> <p>Porażki:</p> <span class="stat-box-special"> {{ resp_json.lost }}</span>
</div> </div>
</div> </div>
</section> </section>
{% endif %} {#{% endif %}#}
{% endfor %} {#{% endfor %}#}
{% endblock %} {% endblock %}
{% block footer %} {% block footer %}

View File

@@ -11,7 +11,7 @@
<p>Gole:</p> <span class="stat-box-special"> {{ nation_stats.goals }} </span> <p>Gole:</p> <span class="stat-box-special"> {{ nation_stats.goals }} </span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Asysty:</p> <span class="stat-box-special"> {{ nation_stats.assists }} </span> <p>Asysty:</p> <span class="stat-box-special"> {{ nation_stats.assist }} </span>
</div> </div>
<div class="stat-box"> <div class="stat-box">
<p>Występy:</p> <span class="stat-box-special"> {{ nation_stats.matches }} </span> <p>Występy:</p> <span class="stat-box-special"> {{ nation_stats.matches }} </span>

View File

@@ -56,7 +56,7 @@
</div> </div>
</section> </section>
<section class="section-stats"> <section class="section-stats">
<h2>Puchary międzynarodowe</h2> <h2>(!) Puchary międzynarodowe</h2>
<div class="stats"> <div class="stats">
<div class="stat-box"> <div class="stat-box">
<h3>{{ international_cups.goals }}</h3> <h3>{{ international_cups.goals }}</h3>
@@ -73,7 +73,7 @@
</div> </div>
</section> </section>
<section class="section-stats"> <section class="section-stats">
<h2>Puchary krajowe</h2> <h2>(!) Puchary krajowe</h2>
<div class="stats"> <div class="stats">
<div class="stat-box"> <div class="stat-box">
<h3>{{ national_cups.goals }}</h3> <h3>{{ national_cups.goals }}</h3>
@@ -103,4 +103,21 @@
</div> </div>
</div> </div>
</section> </section>
<section class="section-stats">
<h2>Wygrane, remisy i przegrane</h2>
<div class="stats">
<div class="stat-box">
<h3>{{ wins_losses.wins }}</h3>
<p>Wygrane</p>
</div>
<div class="stat-box">
<h3>{{ wins_losses.draws }}</h3>
<p>Remisy</p>
</div>
<div class="stat-box">
<h3>{{ wins_losses.losses }}</h3>
<p>Przegrane</p>
</div>
</div>
</section>
{% endblock %} {% endblock %}