From 0fa1697310f639115d5da4322fef322f2dc65e09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Kucharczyk?= Date: Sun, 21 Jun 2026 13:53:00 +0200 Subject: [PATCH] feat(games): honor ?sort= on list_games + eager-load platform (#68) --- games/views/game.py | 9 ++++++++- tests/test_sorting.py | 29 +++++++++++++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/games/views/game.py b/games/views/game.py index ab97034..1386fde 100644 --- a/games/views/game.py +++ b/games/views/game.py @@ -1,5 +1,6 @@ from typing import Any +from django.contrib import messages from django.contrib.auth.decorators import login_required from django.core.paginator import Paginator from django.db.models import Q @@ -48,6 +49,7 @@ from common.time import ( ) from common.utils import build_dynamic_filter, paginate, safe_division, truncate from games.filters import parse_game_filter +from games.sorting import GAME_DEFAULT_SORT, GAME_SORTS, apply_sort, parse_find_filter from games.forms import GameForm from games.models import Game from games.views.general import use_custom_redirect @@ -56,7 +58,7 @@ from games.views.playevent import create_playevent_tabledata @login_required def list_games(request: HttpRequest, search_string: str = "") -> HttpResponse: - games = Game.objects.order_by("-created_at") + games = Game.objects.select_related("platform") # ── Structured filter (Stash-style JSON) ── filter_json = request.GET.get("filter", "") @@ -86,6 +88,11 @@ def list_games(request: HttpRequest, search_string: str = "") -> HttpResponse: filters.append(Q(status=search_status)) games = games.filter(build_dynamic_filter(filters, "|")) + sort = apply_sort(games, parse_find_filter(request), GAME_SORTS, GAME_DEFAULT_SORT) + games = sort.queryset + for key in sort.unknown: + messages.warning(request, f"Unknown sort field '{key}' was ignored.") + games, page_obj, elided_page_range = paginate(request, games) data = { diff --git a/tests/test_sorting.py b/tests/test_sorting.py index b27e5c7..a76bdf2 100644 --- a/tests/test_sorting.py +++ b/tests/test_sorting.py @@ -5,7 +5,9 @@ from zoneinfo import ZoneInfo import pytest from django.conf import settings +from django.contrib.messages import get_messages from django.test import RequestFactory +from django.urls import reverse from games.filters import FindFilter from games.models import Game, Platform, Session @@ -137,3 +139,30 @@ class TestSortMapShapes: ]: for token in default.split(","): assert token.lstrip("-") in sort_map + + +@pytest.fixture +def logged_client(client, django_user_model): + user = django_user_model.objects.create_user(username="u", password="p") + client.force_login(user) + return client + + +class TestListGamesSort: + def test_sort_param_orders_rows(self, logged_client, two_games): + alpha, beta = two_games + response = logged_client.get(reverse("games:list_games"), {"sort": "-name"}) + assert response.status_code == 200 + body = response.content.decode() + assert body.index("Beta") < body.index("Alpha") + + def test_unknown_sort_emits_warning_message(self, logged_client, two_games): + response = logged_client.get(reverse("games:list_games"), {"sort": "bogus"}) + assert response.status_code == 200 + warnings = [str(m) for m in get_messages(response.wsgi_request)] + assert any("bogus" in w for w in warnings) + + def test_valid_sort_emits_no_warning(self, logged_client, two_games): + response = logged_client.get(reverse("games:list_games"), {"sort": "name"}) + warnings = [str(m) for m in get_messages(response.wsgi_request)] + assert warnings == []