Fix #1102: Do not include tracks in album API representation

environments/review-docs-devel-1399dq/deployments/6607
Agate 2020-07-06 10:16:45 +02:00
rodzic 929077594d
commit 55f4fde0f4
16 zmienionych plików z 37 dodań i 86 usunięć

Wyświetl plik

@ -336,6 +336,7 @@ class ManageBaseArtistSerializer(serializers.ModelSerializer):
class ManageBaseAlbumSerializer(serializers.ModelSerializer):
cover = music_serializers.cover_field
domain = serializers.CharField(source="domain_name")
tracks_count = serializers.SerializerMethodField()
class Meta:
model = music_models.Album
@ -349,8 +350,12 @@ class ManageBaseAlbumSerializer(serializers.ModelSerializer):
"cover",
"domain",
"is_local",
"tracks_count",
]
def get_tracks_count(self, o):
return getattr(o, "_tracks_count", None)
class ManageNestedTrackSerializer(serializers.ModelSerializer):
domain = serializers.CharField(source="domain_name")
@ -428,7 +433,6 @@ class ManageNestedArtistSerializer(ManageBaseArtistSerializer):
class ManageAlbumSerializer(
music_serializers.OptionalDescriptionMixin, ManageBaseAlbumSerializer
):
tracks = ManageNestedTrackSerializer(many=True)
attributed_to = ManageBaseActorSerializer()
artist = ManageNestedArtistSerializer()
tags = serializers.SerializerMethodField()
@ -437,7 +441,6 @@ class ManageAlbumSerializer(
model = music_models.Album
fields = ManageBaseAlbumSerializer.Meta.fields + [
"artist",
"tracks",
"attributed_to",
"tags",
]

Wyświetl plik

@ -128,7 +128,7 @@ class ManageAlbumViewSet(
music_models.Album.objects.all()
.order_by("-id")
.select_related("attributed_to", "artist", "attachment_cover")
.prefetch_related("tracks", music_views.TAG_PREFETCH)
.with_tracks_count()
)
serializer_class = serializers.ManageAlbumSerializer
filterset_class = filters.ManageAlbumFilterSet

Wyświetl plik

@ -319,10 +319,6 @@ class AlbumQuerySet(common_models.LocalFromFidQuerySet, models.QuerySet):
else:
return self.exclude(pk__in=matches)
def with_prefetched_tracks_and_playable_uploads(self, actor):
tracks = Track.objects.with_playable_uploads(actor)
return self.prefetch_related(models.Prefetch("tracks", queryset=tracks))
class Album(APIModelMixin):
title = models.CharField(max_length=MAX_LENGTHS["ALBUM_TITLE"])

Wyświetl plik

@ -187,35 +187,12 @@ def serialize_artist_simple(artist):
return data
def serialize_album_track(track):
return {
"id": track.id,
"fid": track.fid,
"mbid": str(track.mbid),
"title": track.title,
"artist": serialize_artist_simple(track.artist),
"album": track.album_id,
"creation_date": DATETIME_FIELD.to_representation(track.creation_date),
"position": track.position,
"disc_number": track.disc_number,
"uploads": [
serialize_upload(u) for u in getattr(track, "playable_uploads", [])
],
"listen_url": track.listen_url,
"duration": getattr(track, "duration", None),
"copyright": track.copyright,
"license": track.license_id,
"is_local": track.is_local,
}
class AlbumSerializer(OptionalDescriptionMixin, serializers.Serializer):
# XXX: remove in 1.0, it's expensive and can work with a filter/api call
tracks = serializers.SerializerMethodField()
artist = serializers.SerializerMethodField()
cover = cover_field
is_playable = serializers.SerializerMethodField()
tags = serializers.SerializerMethodField()
tracks_count = serializers.SerializerMethodField()
attributed_to = serializers.SerializerMethodField()
id = serializers.IntegerField()
fid = serializers.URLField()
@ -232,9 +209,8 @@ class AlbumSerializer(OptionalDescriptionMixin, serializers.Serializer):
def get_artist(self, o):
return serialize_artist_simple(o.artist)
def get_tracks(self, o):
ordered_tracks = o.tracks.all()
return [serialize_album_track(track) for track in ordered_tracks]
def get_tracks_count(self, o):
return getattr(o, "_tracks_count", None)
def get_is_playable(self, obj):
try:

Wyświetl plik

@ -181,6 +181,7 @@ class AlbumViewSet(
queryset = (
models.Album.objects.all()
.order_by("-creation_date")
.with_tracks_count()
.prefetch_related("artist", "attributed_to", "attachment_cover")
)
serializer_class = serializers.AlbumSerializer
@ -217,14 +218,7 @@ class AlbumViewSet(
queryset = queryset.exclude(artist__channel=None).filter(
artist__attributed_to=self.request.user.actor
)
tracks = (
models.Track.objects.prefetch_related("artist")
.with_playable_uploads(utils.get_actor_from_request(self.request))
.order_for_album()
)
qs = queryset.prefetch_related(
Prefetch("tracks", queryset=tracks), TAG_PREFETCH
)
qs = queryset.prefetch_related(TAG_PREFETCH)
return qs
libraries = action(methods=["get"], detail=True)(

Wyświetl plik

@ -373,7 +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)
track = factories["music.Track"](album=album)
setattr(album, "_tracks_count", 42)
expected = {
"id": album.id,
"domain": album.domain_name,
@ -385,11 +385,11 @@ def test_manage_album_serializer(factories, now, to_api_date):
"release_date": album.release_date.isoformat(),
"cover": common_serializers.AttachmentSerializer(album.attachment_cover).data,
"artist": serializers.ManageNestedArtistSerializer(album.artist).data,
"tracks": [serializers.ManageNestedTrackSerializer(track).data],
"attributed_to": serializers.ManageBaseActorSerializer(
album.attributed_to
).data,
"tags": [],
"tracks_count": 42,
}
s = serializers.ManageAlbumSerializer(album)

Wyświetl plik

@ -115,34 +115,6 @@ def test_artist_with_albums_serializer_channel(factories, to_api_date):
assert serializer.data == expected
def test_album_track_serializer(factories, to_api_date):
upload = factories["music.Upload"](
track__license="cc-by-4.0", track__copyright="test", track__disc_number=2
)
track = upload.track
setattr(track, "playable_uploads", [upload])
expected = {
"id": track.id,
"fid": track.fid,
"artist": serializers.serialize_artist_simple(track.artist),
"album": track.album.id,
"mbid": str(track.mbid),
"title": track.title,
"position": track.position,
"disc_number": track.disc_number,
"uploads": [serializers.serialize_upload(upload)],
"creation_date": to_api_date(track.creation_date),
"listen_url": track.listen_url,
"duration": None,
"license": track.license.code,
"copyright": track.copyright,
"is_local": track.is_local,
}
data = serializers.serialize_album_track(track)
assert data == expected
def test_upload_serializer(factories, to_api_date):
upload = factories["music.Upload"]()
@ -200,7 +172,7 @@ def test_album_serializer(factories, to_api_date):
track1 = factories["music.Track"](
position=2, album__attributed_to=actor, album__with_cover=True
)
track2 = factories["music.Track"](position=1, album=track1.album)
factories["music.Track"](position=1, album=track1.album)
album = track1.album
expected = {
"id": album.id,
@ -212,12 +184,14 @@ def test_album_serializer(factories, to_api_date):
"is_playable": False,
"cover": common_serializers.AttachmentSerializer(album.attachment_cover).data,
"release_date": to_api_date(album.release_date),
"tracks": [serializers.serialize_album_track(t) for t in [track2, track1]],
"tracks_count": 2,
"is_local": album.is_local,
"tags": [],
"attributed_to": federation_serializers.APIActorSerializer(actor).data,
}
serializer = serializers.AlbumSerializer(album)
serializer = serializers.AlbumSerializer(
album.__class__.objects.with_tracks_count().get(pk=album.pk)
)
assert serializer.data == expected

Wyświetl plik

@ -57,7 +57,7 @@ def test_album_list_serializer(api_request, factories, logged_in_api_client):
).track
album = track.album
request = api_request.get("/")
qs = album.__class__.objects.with_prefetched_tracks_and_playable_uploads(None)
qs = album.__class__.objects.with_tracks_count()
serializer = serializers.AlbumSerializer(
qs, many=True, context={"request": request}
)

Wyświetl plik

@ -0,0 +1 @@
Do not include tracks in album API representation (#1102)

Wyświetl plik

@ -31,3 +31,11 @@ Now, it returns all the accessible libraries (including ones from other users an
If you are consuming the API via a third-party client and need to retrieve your libraries,
use the ``scope`` parameter, like this: ``GET /api/v1/libraries?scope=me``
API breaking change in ``/api/v1/albums``
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
To increase performance, querying ``/api/v1/albums`` doesn't return album tracks anymore. This caused
some performance issues, especially as some albums and series have dozens or even hundreds of tracks.
If you want to retrieve tracks for an album, you can query ``/api/v1/tracks/?album=<albumid>``.

Wyświetl plik

@ -198,10 +198,9 @@ Album:
- $ref: "#/BaseAlbum"
- type: "object"
properties:
tracks:
type: "array"
items:
$ref: "#/AlbumTrack"
tracks_count:
type: "integer"
format: "int64"
ArtistAlbum:
type: "object"

Wyświetl plik

@ -15,8 +15,8 @@
<div class="description">
<translate translate-context="Content/Channel/Paragraph"
translate-plural="%{ count } episodes"
:translate-n="serie.tracks.length"
:translate-params="{count: serie.tracks.length}">
:translate-n="serie.tracks_count"
:translate-params="{count: serie.tracks_count}">
%{ count } episode
</translate>
</div>

Wyświetl plik

@ -20,7 +20,7 @@
</div>
</div>
<div class="extra content">
<translate translate-context="*/*/*" :translate-params="{count: album.tracks.length}" :translate-n="album.tracks.length" translate-plural="%{ count } tracks">%{ count } track</translate>
<translate translate-context="*/*/*" :translate-params="{count: album.tracks_count}" :translate-n="album.tracks_count" translate-plural="%{ count } tracks">%{ count } track</translate>
<play-button class="right floated basic icon" :dropdown-only="true" :is-playable="album.is_playable" :dropdown-icon-classes="['ellipsis', 'horizontal', 'large really discrete']" :album="album"></play-button>
</div>
</div>

Wyświetl plik

@ -9,7 +9,7 @@
<translate translate-context="*/*/*">None</translate>
</option>
<option v-for="album in albums" :key="album.id" :value="album.id">
{{ album.title }} (<translate translate-context="*/*/*" :translate-params="{count: album.tracks.length}" :translate-n="album.tracks.length" translate-plural="%{ count } tracks">%{ count } track</translate>)
{{ album.title }} (<translate translate-context="*/*/*" :translate-params="{count: album.tracks_count}" :translate-n="album.tracks_count" translate-plural="%{ count } tracks">%{ count } track</translate>)
</option>
</select>
</div>

Wyświetl plik

@ -195,7 +195,7 @@ export default {
},
computed: {
totalTracks () {
return this.object.tracks.length
return this.object.tracks_count
},
isChannel () {
return this.object.artist.channel

Wyświetl plik

@ -67,7 +67,7 @@
</span>
</td>
<td>
{{ scope.obj.tracks.length }}
{{ scope.obj.tracks_count }}
</td>
<td>
<human-date v-if="scope.obj.release_date" :date="scope.obj.release_date"></human-date>