From 1295144681c26a7ad99bc652271cfd957c8b427d Mon Sep 17 00:00:00 2001
From: Agate <me@agate.blue>
Date: Thu, 9 Jul 2020 11:51:58 +0200
Subject: [PATCH] Fixed really slow SQL

---
 api/funkwhale_api/manage/serializers.py       |  4 ++++
 api/funkwhale_api/manage/views.py             |  2 +-
 api/funkwhale_api/music/serializers.py        |  4 ++--
 api/funkwhale_api/music/views.py              | 16 +++++++++-------
 api/tests/manage/test_serializers.py          |  3 ++-
 front/src/views/admin/library/AlbumDetail.vue |  2 +-
 6 files changed, 19 insertions(+), 12 deletions(-)

diff --git a/api/funkwhale_api/manage/serializers.py b/api/funkwhale_api/manage/serializers.py
index d8cab97312..de7d7d63be 100644
--- a/api/funkwhale_api/manage/serializers.py
+++ b/api/funkwhale_api/manage/serializers.py
@@ -443,8 +443,12 @@ class ManageAlbumSerializer(
             "artist",
             "attributed_to",
             "tags",
+            "tracks_count",
         ]
 
+    def get_tracks_count(self, o):
+        return len(o.tracks.all())
+
     def get_tags(self, obj):
         tagged_items = getattr(obj, "_prefetched_tagged_items", [])
         return [ti.tag.name for ti in tagged_items]
diff --git a/api/funkwhale_api/manage/views.py b/api/funkwhale_api/manage/views.py
index bc3908daee..52bdfaf244 100644
--- a/api/funkwhale_api/manage/views.py
+++ b/api/funkwhale_api/manage/views.py
@@ -128,7 +128,7 @@ class ManageAlbumViewSet(
         music_models.Album.objects.all()
         .order_by("-id")
         .select_related("attributed_to", "artist", "attachment_cover")
-        .with_tracks_count()
+        .prefetch_related("tracks")
     )
     serializer_class = serializers.ManageAlbumSerializer
     filterset_class = filters.ManageAlbumFilterSet
diff --git a/api/funkwhale_api/music/serializers.py b/api/funkwhale_api/music/serializers.py
index 7dfef3bcac..7d894b5eda 100644
--- a/api/funkwhale_api/music/serializers.py
+++ b/api/funkwhale_api/music/serializers.py
@@ -101,7 +101,7 @@ class ArtistAlbumSerializer(serializers.Serializer):
         return o.artist_id
 
     def get_tracks_count(self, o):
-        return o._tracks_count
+        return len(o.tracks.all())
 
     def get_is_playable(self, obj):
         try:
@@ -210,7 +210,7 @@ class AlbumSerializer(OptionalDescriptionMixin, serializers.Serializer):
         return serialize_artist_simple(o.artist)
 
     def get_tracks_count(self, o):
-        return getattr(o, "_tracks_count", None)
+        return len(o.tracks.all())
 
     def get_is_playable(self, obj):
         try:
diff --git a/api/funkwhale_api/music/views.py b/api/funkwhale_api/music/views.py
index 5a4e81da4b..2b4af7ae64 100644
--- a/api/funkwhale_api/music/views.py
+++ b/api/funkwhale_api/music/views.py
@@ -152,8 +152,10 @@ class ArtistViewSet(
 
     def get_queryset(self):
         queryset = super().get_queryset()
-        albums = models.Album.objects.with_tracks_count().select_related(
-            "attachment_cover"
+        albums = (
+            models.Album.objects.with_tracks_count()
+            .select_related("attachment_cover")
+            .prefetch_related("tracks")
         )
         albums = albums.annotate_playable_by_actor(
             utils.get_actor_from_request(self.request)
@@ -179,10 +181,10 @@ class AlbumViewSet(
     viewsets.ReadOnlyModelViewSet,
 ):
     queryset = (
-        models.Album.objects.all()
-        .order_by("-creation_date")
-        .with_tracks_count()
-        .prefetch_related("artist", "attributed_to", "attachment_cover")
+        models.Album.objects.all().order_by("-creation_date")
+        # we do a prefetech related on tracks instead of a count because it's more efficient
+        # db-wise
+        .prefetch_related("artist", "attributed_to", "attachment_cover", "tracks")
     )
     serializer_class = serializers.AlbumSerializer
     permission_classes = [oauth_permissions.ScopePermission]
@@ -759,7 +761,7 @@ class Search(views.APIView):
                     "album",
                     queryset=models.Album.objects.select_related(
                         "artist", "attachment_cover", "attributed_to"
-                    ),
+                    ).prefetch_related("tracks"),
                 ),
             )
         )
diff --git a/api/tests/manage/test_serializers.py b/api/tests/manage/test_serializers.py
index d6de65a47e..6ba29897ef 100644
--- a/api/tests/manage/test_serializers.py
+++ b/api/tests/manage/test_serializers.py
@@ -373,6 +373,7 @@ def test_manage_nested_artist_serializer(factories, now, to_api_date):
 
 def test_manage_album_serializer(factories, now, to_api_date):
     album = factories["music.Album"](attributed=True, with_cover=True)
+    factories["music.Track"](album=album)
     setattr(album, "_tracks_count", 42)
     expected = {
         "id": album.id,
@@ -389,7 +390,7 @@ def test_manage_album_serializer(factories, now, to_api_date):
             album.attributed_to
         ).data,
         "tags": [],
-        "tracks_count": 42,
+        "tracks_count": 1,
     }
     s = serializers.ManageAlbumSerializer(album)
 
diff --git a/front/src/views/admin/library/AlbumDetail.vue b/front/src/views/admin/library/AlbumDetail.vue
index d1a07da37e..8f10600734 100644
--- a/front/src/views/admin/library/AlbumDetail.vue
+++ b/front/src/views/admin/library/AlbumDetail.vue
@@ -276,7 +276,7 @@
                       </router-link>
                     </td>
                     <td>
-                      {{ object.tracks.length }}
+                      {{ object.tracks_count }}
                     </td>
                   </tr>
                 </tbody>
-- 
GitLab