Align balldontlie OpenAPI integration and clarify search metric semantics

This commit is contained in:
Alfredo Di Stasio
2026-03-12 16:37:02 +01:00
parent c9dd10a438
commit dac63f9148
16 changed files with 1562 additions and 82 deletions

View File

@ -13,10 +13,10 @@ class PlayerSearchForm(forms.Form):
("age_oldest", "Age (Oldest first)"),
("height_desc", "Height (Tallest first)"),
("height_asc", "Height (Shortest first)"),
("ppg_desc", "Points per game (High to low)"),
("ppg_asc", "Points per game (Low to high)"),
("mpg_desc", "Minutes per game (High to low)"),
("mpg_asc", "Minutes per game (Low to high)"),
("ppg_desc", "Best eligible PPG (High to low)"),
("ppg_asc", "Best eligible PPG (Low to high)"),
("mpg_desc", "Best eligible MPG (High to low)"),
("mpg_asc", "Best eligible MPG (Low to high)"),
)
PAGE_SIZE_CHOICES = ((20, "20"), (50, "50"), (100, "100"))

View File

@ -20,6 +20,10 @@ from apps.players.models import Player
from apps.stats.models import PlayerSeason
METRIC_SORT_KEYS = {"ppg_desc", "ppg_asc", "mpg_desc", "mpg_asc"}
SEARCH_METRIC_SEMANTICS_TEXT = (
"Search metrics are best eligible values per player (max per metric across eligible player-season rows). "
"With season/team/competition/stat filters, eligibility is scoped by those filters."
)
def _years_ago_today(years: int) -> date:
@ -213,6 +217,13 @@ def filter_players(queryset, data: dict):
def annotate_player_metrics(queryset, data: dict | None = None):
"""
Annotate player list metrics using best-eligible semantics.
Each metric is computed as MAX over eligible player-season rows. This is intentionally
not a single-row projection; different displayed metrics for one player can come from
different eligible player-season rows.
"""
data = data or {}
context_filter = _build_metric_context_filter(data)

View File

@ -8,7 +8,13 @@ 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
from .services.search import (
SEARCH_METRIC_SEMANTICS_TEXT,
annotate_player_metrics,
apply_sorting,
base_player_queryset,
filter_players,
)
def calculate_age(birth_date):
@ -61,6 +67,7 @@ class PlayerSearchView(ListView):
search_form = self.get_form()
context["search_form"] = search_form
context["search_has_errors"] = search_form.is_bound and bool(search_form.errors)
context["search_metric_semantics"] = SEARCH_METRIC_SEMANTICS_TEXT
context["favorite_player_ids"] = set()
if self.request.user.is_authenticated:
player_ids = [player.id for player in context["players"]]