Browse Source

Add filterable lists

Colin Powell 3 years ago
parent
commit
c0693d88a2

+ 20 - 1
games/urls.py

@@ -18,6 +18,21 @@ urlpatterns = [
         views.LibraryGameList.as_view(),
         views.LibraryGameList.as_view(),
         name="game_library_list",
         name="game_library_list",
     ),
     ),
+    path(
+        "publisher/",
+        views.PublisherList.as_view(),
+        name="publisher_list",
+    ),
+    path(
+        "genre/",
+        views.GenreList.as_view(),
+        name="genre_list",
+    ),
+    path(
+        "developer/",
+        views.DeveloperList.as_view(),
+        name="developer_list",
+    ),
     path(
     path(
         "<str:slug>/",
         "<str:slug>/",
         views.GameDetail.as_view(),
         views.GameDetail.as_view(),
@@ -33,7 +48,11 @@ urlpatterns = [
         views.GameSystemDetail.as_view(),
         views.GameSystemDetail.as_view(),
         name="game_system_detail",
         name="game_system_detail",
     ),
     ),
-    path("genre/<str:slug>/", views.GenreDetail.as_view(), name="genre_detail"),
+    path(
+        "genre/<str:slug>/",
+        views.GenreDetail.as_view(),
+        name="genre_detail",
+    ),
     path(
     path(
         "publisher/<str:slug>/",
         "publisher/<str:slug>/",
         views.PublisherDetail.as_view(),
         views.PublisherDetail.as_view(),

+ 46 - 4
games/views.py

@@ -1,24 +1,33 @@
-from django.db.models import F
+from django.db.models import Avg, Count, F
 from django.views.generic import DetailView, ListView
 from django.views.generic import DetailView, ListView
 from django.views.generic.list import MultipleObjectMixin
 from django.views.generic.list import MultipleObjectMixin
 
 
 from .models import Developer, Game, GameSystem, Genre, Publisher
 from .models import Developer, Game, GameSystem, Genre, Publisher
 
 
+import logging
+
+logger = logging.Logger(__name__)
+
 
 
 class RecentGameList(ListView):
 class RecentGameList(ListView):
     model = Game
     model = Game
     paginate_by = 20
     paginate_by = 20
-    queryset = Game.objects.order_by("-created")[:20]
+    queryset = Game.objects.order_by("-created")[:200]
 
 
 
 
 class LibraryGameList(ListView):
 class LibraryGameList(ListView):
     template_name = "games/game_library_list.html"
     template_name = "games/game_library_list.html"
     model = Game
     model = Game
-    paginate_by = 200
+    paginate_by = 100
 
 
     def get_context_data(self, **kwargs):
     def get_context_data(self, **kwargs):
         game_system_slug = self.request.GET.get("game_system")
         game_system_slug = self.request.GET.get("game_system")
-        object_list = Game.objects.order_by(F("rating").desc(nulls_last=True))
+        order_by = self.request.GET.get("order_by", "name")
+        if order_by[0] == "-":
+            order_by = order_by[1:]
+            object_list = Game.objects.order_by(F(order_by).desc(nulls_last=True))
+        else:
+            object_list = Game.objects.order_by(F(order_by).asc(nulls_last=True))
         if game_system_slug:
         if game_system_slug:
             object_list = object_list.filter(
             object_list = object_list.filter(
                 game_system__retropie_slug=game_system_slug
                 game_system__retropie_slug=game_system_slug
@@ -29,6 +38,39 @@ class LibraryGameList(ListView):
         return context
         return context
 
 
 
 
+class FilterableBaseListView(ListView):
+    VALID_ORDERING = ["name", "num_games", "rating"]
+
+    def get_queryset(self, **kwargs):
+        order_by = self.request.GET.get("order_by", "name")
+        queryset = super().get_queryset(**kwargs)
+        queryset = queryset.annotate(num_games=Count("game")).annotate(
+            rating=Avg("game__rating")
+        )
+        if order_by.replace("-", "") not in self.VALID_ORDERING:
+            logger.warning(f"Received invalid filter {order_by}")
+            return queryset
+
+        if order_by[0] == "-":
+            order_by = order_by[1:]
+            queryset = queryset.order_by(F(order_by).desc(nulls_last=True))
+        else:
+            queryset = queryset.order_by(F(order_by).asc(nulls_last=True))
+        return queryset
+
+
+class PublisherList(FilterableBaseListView):
+    model = Publisher
+
+
+class DeveloperList(FilterableBaseListView):
+    model = Developer
+
+
+class GenreList(FilterableBaseListView):
+    model = Genre
+
+
 class GameDetail(DetailView):
 class GameDetail(DetailView):
     model = Game
     model = Game
 
 

+ 27 - 0
templates/games/developer_list.html

@@ -0,0 +1,27 @@
+{% extends "base.html" %}
+{% block page_title %}Developers{% endblock %}
+
+{% block title %}All developers{% endblock %}
+
+{% block content %}
+    <table class="table table-bordered table">
+    <thead>
+        <tr>
+        <th scope="col">#</th>
+        <th scope="col">Name</th>
+        <th scope="col">Games</th>
+        <th scope="col">Rating</th>
+        </tr>
+    </thead>
+    <tbody>
+        {% for  developer in object_list %}
+        <tr>
+        <th scope="row"><a href="{{developer.get_absolute_url}}">{{developer.id}}</a></th>
+        <td>{{developer.name}}</td>
+        <td>{{developer.game_set.count}}</td>
+        <td>{{developer.rating_avg}}/100</td>
+        </tr>
+        {% endfor %}
+    </tbody>
+    </table>
+{% endblock %}

+ 5 - 5
templates/games/game_library_list.html

@@ -8,12 +8,12 @@
     <thead>
     <thead>
         <tr>
         <tr>
         <th scope="col">#</th>
         <th scope="col">#</th>
-        <th scope="col">Name</th>
+        <th scope="col"><a href="?order_by=name">Name</a></th>
         <th scope="col">System</th>
         <th scope="col">System</th>
-        <th scope="col">Rating</th>
-        <th scope="col">Developer</th>
-        <th scope="col">Publisher</th>
-        <th scope="col">Genre</th>
+        <th scope="col"><a href="?order_by={% if not '-rating' in request.get_full_path %}-{% endif %}rating">Rating</a></th>
+        <th scope="col"><a href="?order_by={% if not '-developer' in request.get_full_path %}-{% endif %}developer">Developer</a></th>
+        <th scope="col"><a href="?order_by={% if not '-publisher' in request.get_full_path %}-{% endif %}publisher">Publisher</a></th>
+        <th scope="col"><a href="?order_by={% if not '-genre' in request.get_full_path %}-{% endif %}genre">Genre</a></th>
         </tr>
         </tr>
     </thead>
     </thead>
     <tbody>
     <tbody>

+ 27 - 0
templates/games/genre_list.html

@@ -0,0 +1,27 @@
+{% extends "base.html" %}
+{% block page_title %}Genres{% endblock %}
+
+{% block title %}All genres{% endblock %}
+
+{% block content %}
+    <table class="table table-bordered table">
+    <thead>
+        <tr>
+        <th scope="col">#</th>
+        <th scope="col">Name</th>
+        <th scope="col">Games</th>
+        <th scope="col">Rating</th>
+        </tr>
+    </thead>
+    <tbody>
+        {% for  genre in object_list %}
+        <tr>
+        <th scope="row"><a href="{{genre.get_absolute_url}}">{{genre.id}}</a></th>
+        <td>{{genre.name}}</td>
+        <td>{{genre.game_set.count}}</td>
+        <td>{{genre.rating_avg}}/100</td>
+        </tr>
+        {% endfor %}
+    </tbody>
+    </table>
+{% endblock %}

+ 27 - 0
templates/games/publisher_list.html

@@ -0,0 +1,27 @@
+{% extends "base.html" %}
+{% block page_title %}Publishers{% endblock %}
+
+{% block title %}All publishers{% endblock %}
+
+{% block content %}
+    <table class="table table-bordered table">
+    <thead>
+        <tr>
+        <th scope="col">#</th>
+        <th scope="col">Name</th>
+        <th scope="col">Games</th>
+        <th scope="col">Rating</th>
+        </tr>
+    </thead>
+    <tbody>
+        {% for  publisher in object_list %}
+        <tr>
+        <th scope="row"><a href="{{publisher.get_absolute_url}}">{{publisher.id}}</a></th>
+        <td>{{publisher.name}}</td>
+        <td>{{publisher.game_set.count}}</td>
+        <td>{{publisher.rating_avg}}/100</td>
+        </tr>
+        {% endfor %}
+    </tbody>
+    </table>
+{% endblock %}