Added a v3 standings page #514
No reviewers
Labels
No labels
Kestra
bug
enhancement
someday
subtask
☁️ api
🎛️ infrastructure
🐞 sentry
📆 2025 Season
📝 pages
allpicks
📝 pages
picks
📝 pages
standings
🚀 performance
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
johnsturgeon/tgfp-web!514
Loading…
Reference in a new issue
No description provided.
Delete branch "implement-v3-standings-page-513"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Also fixed a bug in the menu where it folded under the table header row
Resolves #513
This is a clean, well-tested PR. I inspected the route, the new
PlayerAward.by_player_for_weekhelper, the models it leans on, and the template.Summary
PR #514 adds a v3 standings page that renders one row per active player with season totals, this-week record, and award icons, plus a small nav z-index fix and a font-weight tweak. The data access is deliberately batched (one query for picks, one for awards, cache-warmed games/teams) and the query-count regression test is a genuinely good guard; I found no blocking issues.
Worth fixing
app/routers/v3.py:125— the awards legend query runs unordered (select(Award)), so the icon legend row order is nondeterministic across DB restarts/backends. If the header legend should read in a stable order (e.g. bypoint_valueorslug), add an.order_by(...). Minor, but the picks/standings pages generally present awards consistently.Nits
The whole "no N+1" property rests on an implicit coupling:
by_player_for_weekdoesn't eager-loadPlayerAward.award, soplayer_award.award.icon/.nameinapp/templates/v3/standings.html:39only stay free because the route eagerly runsselect(Award)(line 125) first and populates the identity map. That's correct today and the cost test locks it in, but it's fragile — if someone later drops the legend query, the page silently regresses to a lazy load per award row. A one-line comment onby_player_for_week(or aselectinloadonaward) would make the intent self-documenting.app/templates/v3/standings.html:74computes the Total column asplayer.wins + player.bonuswhile games-back on line 78 usesplayer.total_points. They're identical today (total_pointsis defined aswins + bonusinapp/models/player.py:65), but usingplayer.total_pointsin both spots removes the drift risk and reads more clearly.by_player_for_weekreturns everyPlayerAwardrow for the week, including per-game awards (in_your_facehas a non-nullgame_id). A player who earned the same per-game award on two games this week would render two identical icons with the same alt/title. If that's intended (each is a distinct achievement), ignore this; otherwise you may want to de-dup by award for the icon strip. The tests only cover a single week-level award, so this case is unexercised.winning_pctreturnsNonefor a player with no games (app/models/player.py:147); the template's| floatfilter coerces that to0.0, so the page is safe — worth a quick mental note that the same value is not guarded instandings_email.py's:.3fformat (pre-existing, out of scope here).Nice touch on the cost test asserting
large == smallrather than a magic number — that's the right way to express "doesn't scale with the pool."