See #224: less clutered music API, better serializers

This commit is contained in:
Eliot Berriot 2018-05-22 21:10:48 +02:00
commit 857fab526d
No known key found for this signature in database
GPG key ID: DD6965E2476E5C27
14 changed files with 318 additions and 122 deletions

View file

@ -3,7 +3,6 @@ from django.conf import settings
from rest_framework import serializers
from funkwhale_api.activity import serializers as activity_serializers
from funkwhale_api.music.serializers import TrackSerializerNested
from funkwhale_api.music.serializers import TrackActivitySerializer
from funkwhale_api.users.serializers import UserActivitySerializer
@ -35,7 +34,6 @@ class TrackFavoriteActivitySerializer(activity_serializers.ModelSerializer):
class UserTrackFavoriteSerializer(serializers.ModelSerializer):
# track = TrackSerializerNested(read_only=True)
class Meta:
model = models.TrackFavorite
fields = ('id', 'track', 'creation_date')

View file

@ -1,7 +1,6 @@
from rest_framework import serializers
from funkwhale_api.activity import serializers as activity_serializers
from funkwhale_api.music.serializers import TrackSerializerNested
from funkwhale_api.music.serializers import TrackActivitySerializer
from funkwhale_api.users.serializers import UserActivitySerializer

View file

@ -6,7 +6,6 @@ from rest_framework.decorators import detail_route
from funkwhale_api.activity import record
from funkwhale_api.common.permissions import ConditionalAuthentication
from funkwhale_api.music.serializers import TrackSerializerNested
from . import models
from . import serializers

View file

@ -80,6 +80,12 @@ class ArtistQuerySet(models.QuerySet):
def with_albums_count(self):
return self.annotate(_albums_count=models.Count('albums'))
def with_albums(self):
return self.prefetch_related(
models.Prefetch(
'albums', queryset=Album.objects.with_tracks_count())
)
class Artist(APIModelMixin):
name = models.CharField(max_length=255)

View file

@ -13,24 +13,38 @@ from . import models
from . import tasks
class TagSerializer(serializers.ModelSerializer):
class ArtistAlbumSerializer(serializers.ModelSerializer):
tracks_count = serializers.SerializerMethodField()
class Meta:
model = Tag
fields = ('id', 'name', 'slug')
model = models.Album
fields = (
'id',
'mbid',
'title',
'artist',
'release_date',
'cover',
'creation_date',
'tracks_count',
)
def get_tracks_count(self, o):
return o._tracks_count
class SimpleArtistSerializer(serializers.ModelSerializer):
class Meta:
model = models.Artist
fields = ('id', 'mbid', 'name', 'creation_date')
class ArtistSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
class ArtistWithAlbumsSerializer(serializers.ModelSerializer):
albums = ArtistAlbumSerializer(many=True, read_only=True)
class Meta:
model = models.Artist
fields = ('id', 'mbid', 'name', 'tags', 'creation_date')
fields = (
'id',
'mbid',
'name',
'creation_date',
'albums',
)
class TrackFileSerializer(serializers.ModelSerializer):
@ -62,71 +76,107 @@ class TrackFileSerializer(serializers.ModelSerializer):
return url
class SimpleAlbumSerializer(serializers.ModelSerializer):
class Meta:
model = models.Album
fields = ('id', 'mbid', 'title', 'release_date', 'cover')
class AlbumSerializer(serializers.ModelSerializer):
tags = TagSerializer(many=True, read_only=True)
class Meta:
model = models.Album
fields = ('id', 'mbid', 'title', 'cover', 'release_date', 'tags')
class LyricsMixin(serializers.ModelSerializer):
lyrics = serializers.SerializerMethodField()
def get_lyrics(self, obj):
return obj.get_lyrics_url()
class TrackSerializer(LyricsMixin):
class AlbumTrackSerializer(serializers.ModelSerializer):
files = TrackFileSerializer(many=True, read_only=True)
tags = TagSerializer(many=True, read_only=True)
class Meta:
model = models.Track
fields = (
'id',
'mbid',
'title',
'album',
'artist',
'creation_date',
'files',
'tags',
'position',
'lyrics')
)
class TrackSerializerNested(LyricsMixin):
artist = ArtistSerializer()
files = TrackFileSerializer(many=True, read_only=True)
album = SimpleAlbumSerializer(read_only=True)
tags = TagSerializer(many=True, read_only=True)
class ArtistSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = models.Track
fields = ('id', 'mbid', 'title', 'artist', 'files', 'album', 'tags', 'lyrics')
model = models.Artist
fields = (
'id',
'mbid',
'name',
'creation_date',
)
class AlbumSerializerNested(serializers.ModelSerializer):
tracks = TrackSerializer(many=True, read_only=True)
artist = SimpleArtistSerializer()
tags = TagSerializer(many=True, read_only=True)
class AlbumSerializer(serializers.ModelSerializer):
tracks = serializers.SerializerMethodField()
artist = ArtistSimpleSerializer(read_only=True)
class Meta:
model = models.Album
fields = ('id', 'mbid', 'title', 'cover', 'artist', 'release_date', 'tracks', 'tags')
fields = (
'id',
'mbid',
'title',
'artist',
'tracks',
'release_date',
'cover',
'creation_date',
)
def get_tracks(self, o):
ordered_tracks = sorted(o.tracks.all(), key=lambda v: v.position)
return AlbumTrackSerializer(ordered_tracks, many=True).data
class ArtistSerializerNested(serializers.ModelSerializer):
albums = AlbumSerializerNested(many=True, read_only=True)
tags = TagSerializer(many=True, read_only=True)
class TrackAlbumSerializer(serializers.ModelSerializer):
artist = ArtistSimpleSerializer(read_only=True)
class Meta:
model = models.Artist
fields = ('id', 'mbid', 'name', 'albums', 'tags')
model = models.Album
fields = (
'id',
'mbid',
'title',
'artist',
'release_date',
'cover',
'creation_date',
)
class TrackSerializer(serializers.ModelSerializer):
files = TrackFileSerializer(many=True, read_only=True)
artist = ArtistSimpleSerializer(read_only=True)
album = TrackAlbumSerializer(read_only=True)
lyrics = serializers.SerializerMethodField()
class Meta:
model = models.Track
fields = (
'id',
'mbid',
'title',
'album',
'artist',
'creation_date',
'files',
'position',
'lyrics',
)
def get_lyrics(self, obj):
return obj.get_lyrics_url()
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ('id', 'name', 'slug')
class SimpleAlbumSerializer(serializers.ModelSerializer):
class Meta:
model = models.Album
fields = ('id', 'mbid', 'title', 'release_date', 'cover')
class LyricsSerializer(serializers.ModelSerializer):

View file

@ -68,13 +68,8 @@ class TagViewSetMixin(object):
class ArtistViewSet(SearchMixin, viewsets.ReadOnlyModelViewSet):
queryset = (
models.Artist.objects.all()
.prefetch_related(
'albums__tracks__files',
'albums__tracks__artist',
'albums__tracks__tags'))
serializer_class = serializers.ArtistSerializerNested
queryset = models.Artist.objects.with_albums()
serializer_class = serializers.ArtistWithAlbumsSerializer
permission_classes = [ConditionalAuthentication]
search_fields = ['name__unaccent']
filter_class = filters.ArtistFilter
@ -88,7 +83,7 @@ class AlbumViewSet(SearchMixin, viewsets.ReadOnlyModelViewSet):
.select_related()
.prefetch_related('tracks__tags',
'tracks__files'))
serializer_class = serializers.AlbumSerializerNested
serializer_class = serializers.AlbumSerializer
permission_classes = [ConditionalAuthentication]
search_fields = ['title__unaccent']
ordering_fields = ('creation_date',)
@ -166,7 +161,7 @@ class TrackViewSet(
A simple ViewSet for viewing and editing accounts.
"""
queryset = (models.Track.objects.all().for_nested_serialization())
serializer_class = serializers.TrackSerializerNested
serializer_class = serializers.TrackSerializer
permission_classes = [ConditionalAuthentication]
search_fields = ['title', 'artist__name']
ordering_fields = (
@ -370,10 +365,10 @@ class Search(views.APIView):
def get(self, request, *args, **kwargs):
query = request.GET['query']
results = {
'tags': serializers.TagSerializer(self.get_tags(query), many=True).data,
'artists': serializers.ArtistSerializerNested(self.get_artists(query), many=True).data,
'tracks': serializers.TrackSerializerNested(self.get_tracks(query), many=True).data,
'albums': serializers.AlbumSerializerNested(self.get_albums(query), many=True).data,
# 'tags': serializers.TagSerializer(self.get_tags(query), many=True).data,
'artists': serializers.ArtistWithAlbumsSerializer(self.get_artists(query), many=True).data,
'tracks': serializers.TrackSerializer(self.get_tracks(query), many=True).data,
'albums': serializers.AlbumSerializer(self.get_albums(query), many=True).data,
}
return Response(results, status=200)
@ -387,14 +382,10 @@ class Search(views.APIView):
return (
models.Track.objects.all()
.filter(query_obj)
.select_related('album__artist')
.prefetch_related(
'tags',
'artist__albums__tracks__tags',
'files')
.select_related('artist', 'album__artist')
.prefetch_related('files')
)[:self.max_results]
def get_albums(self, query):
search_fields = [
'mbid',
@ -406,27 +397,19 @@ class Search(views.APIView):
.filter(query_obj)
.select_related()
.prefetch_related(
'tracks__tags',
'tracks__files',
)
)
)[:self.max_results]
def get_artists(self, query):
search_fields = ['mbid', 'name__unaccent']
query_obj = utils.get_query(query, search_fields)
return (
models.Artist.objects.all()
.filter(query_obj)
.select_related()
.prefetch_related(
'albums__tracks__tags',
'albums__tracks__files',
)
.with_albums()
)[:self.max_results]
def get_tags(self, query):
search_fields = ['slug', 'name__unaccent']
query_obj = utils.get_query(query, search_fields)

View file

@ -5,13 +5,13 @@ from taggit.models import Tag
from funkwhale_api.common import preferences
from funkwhale_api.music.models import Track
from funkwhale_api.music.serializers import TrackSerializerNested
from funkwhale_api.music.serializers import TrackSerializer
from funkwhale_api.users.serializers import UserBasicSerializer
from . import models
class PlaylistTrackSerializer(serializers.ModelSerializer):
track = TrackSerializerNested()
track = TrackSerializer()
class Meta:
model = models.PlaylistTrack

View file

@ -1,6 +1,6 @@
from rest_framework import serializers
from funkwhale_api.music.serializers import TrackSerializerNested
from funkwhale_api.music.serializers import TrackSerializer
from funkwhale_api.users.serializers import UserBasicSerializer
from . import filters
@ -46,7 +46,7 @@ class RadioSessionTrackSerializerCreate(serializers.ModelSerializer):
class RadioSessionTrackSerializer(serializers.ModelSerializer):
track = TrackSerializerNested()
track = TrackSerializer()
class Meta:
model = models.RadioSessionTrack

View file

@ -7,7 +7,7 @@ from rest_framework import status
from rest_framework.response import Response
from rest_framework.decorators import detail_route, list_route
from funkwhale_api.music.serializers import TrackSerializerNested
from funkwhale_api.music.serializers import TrackSerializer
from funkwhale_api.common.permissions import ConditionalAuthentication
from . import models
@ -49,7 +49,7 @@ class RadioViewSet(
page = self.paginate_queryset(tracks)
if page is not None:
serializer = TrackSerializerNested(page, many=True)
serializer = TrackSerializer(page, many=True)
return self.get_paginated_response(serializer.data)
@list_route(methods=['get'])
@ -72,7 +72,7 @@ class RadioViewSet(
results = filters.test(f)
if results['candidates']['sample']:
qs = results['candidates']['sample'].for_nested_serialization()
results['candidates']['sample'] = TrackSerializerNested(
results['candidates']['sample'] = TrackSerializer(
qs, many=True).data
data['filters'].append(results)