feat: add scouting search sorting and pagination

This commit is contained in:
bisco
2026-04-07 17:18:36 +02:00
parent 6c53cae7a1
commit 6d8af021ce
4 changed files with 270 additions and 5 deletions

View File

@ -1,11 +1,85 @@
from __future__ import annotations
from decimal import Decimal
from django.core.paginator import Paginator
from django.db.models import Exists, OuterRef, Prefetch
from django.shortcuts import get_object_or_404, render
from .forms import PlayerSearchForm
from .models import Player, PlayerSeason
PAGE_SIZE = 20
PLAYER_SORTS = {
"name_asc",
"name_desc",
"age_youngest",
"height_desc",
"weight_desc",
}
CONTEXT_SORTS = {
"points_desc": "points",
"assists_desc": "assists",
"ts_pct_desc": "ts_pct",
"blocks_desc": "blocks",
}
def sort_players(players, sort_key: str, context_filters_used: bool):
if sort_key not in PLAYER_SORTS | set(CONTEXT_SORTS):
sort_key = "name_asc"
if sort_key == "name_asc":
players.sort(key=lambda player: player.full_name.casefold())
return sort_key
if sort_key == "name_desc":
players.sort(key=lambda player: player.full_name.casefold(), reverse=True)
return sort_key
if sort_key == "age_youngest":
players.sort(
key=lambda player: (
player.birth_date is None,
-(player.birth_date.toordinal()) if player.birth_date else 0,
player.full_name.casefold(),
)
)
return sort_key
if sort_key == "height_desc":
players.sort(
key=lambda player: (
player.height_cm is None,
-(player.height_cm or Decimal("0")),
player.full_name.casefold(),
)
)
return sort_key
if sort_key == "weight_desc":
players.sort(
key=lambda player: (
player.weight_kg is None,
-(player.weight_kg or Decimal("0")),
player.full_name.casefold(),
)
)
return sort_key
if not context_filters_used:
players.sort(key=lambda player: player.full_name.casefold())
return "name_asc"
stat_name = CONTEXT_SORTS[sort_key]
players.sort(
key=lambda player: (
getattr(getattr(getattr(player, "matching_context", None), "stats", None), stat_name, None) is None,
-(
getattr(getattr(getattr(player, "matching_context", None), "stats", None), stat_name)
or Decimal("0")
),
player.full_name.casefold(),
)
)
return sort_key
def player_list(request):
form = PlayerSearchForm(request.GET or None)
@ -15,9 +89,11 @@ def player_list(request):
.order_by("full_name")
)
context_filters_used = False
requested_sort = request.GET.get("sort") or "name_asc"
if form.is_valid():
data = form.cleaned_data
requested_sort = data["sort"] or "name_asc"
if data["name"]:
queryset = queryset.filter(full_name__icontains=data["name"])
@ -153,12 +229,23 @@ def player_list(request):
for player in players:
player.matching_context = next(iter(player.matching_contexts), None)
active_sort = sort_players(players, requested_sort, context_filters_used)
paginator = Paginator(players, PAGE_SIZE)
page_obj = paginator.get_page(request.GET.get("page"))
query_without_page = request.GET.copy()
query_without_page.pop("page", None)
return render(
request,
"scouting/player_list.html",
{
"form": form,
"players": players,
"players": page_obj.object_list,
"page_obj": page_obj,
"active_sort": active_sort,
"total_results": paginator.count,
"query_without_page": query_without_page.urlencode(),
"context_sorting_enabled": context_filters_used,
},
)