mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-12-01 01:43:44 +03:00
Compare commits
No commits in common. "debdf53927660ab665b750fb5b755bd499454a68" and "0aef69b754f0cee67b970fc508a02f5a30aafcbe" have entirely different histories.
debdf53927
...
0aef69b754
|
@ -1,7 +1,5 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from akarpov.utils.models import get_model_user_field
|
|
||||||
|
|
||||||
|
|
||||||
class RecursiveField(serializers.Serializer):
|
class RecursiveField(serializers.Serializer):
|
||||||
def to_representation(self, value):
|
def to_representation(self, value):
|
||||||
|
@ -11,19 +9,6 @@ def to_representation(self, value):
|
||||||
|
|
||||||
class SetUserModelSerializer(serializers.ModelSerializer):
|
class SetUserModelSerializer(serializers.ModelSerializer):
|
||||||
def create(self, validated_data):
|
def create(self, validated_data):
|
||||||
if self.context["request"].user.is_authenticated:
|
|
||||||
creator = self.context["request"].user
|
creator = self.context["request"].user
|
||||||
else:
|
obj = self.Meta.model.objects.create(creator=creator, **validated_data)
|
||||||
creator = None
|
|
||||||
validated_data[
|
|
||||||
get_model_user_field(
|
|
||||||
self.Meta.model._meta.app_label, self.Meta.model._meta.model_name
|
|
||||||
)
|
|
||||||
] = creator
|
|
||||||
try:
|
|
||||||
obj = self.Meta.model.objects.create(**validated_data)
|
|
||||||
except TypeError:
|
|
||||||
raise serializers.ValidationError(
|
|
||||||
{"detail": "You need to login to create this object"}
|
|
||||||
)
|
|
||||||
return obj
|
return obj
|
||||||
|
|
|
@ -1,9 +0,0 @@
|
||||||
from django_filters import rest_framework as filters
|
|
||||||
|
|
||||||
from akarpov.music.models import Playlist
|
|
||||||
|
|
||||||
|
|
||||||
class PlaylistFilter(filters.FilterSet):
|
|
||||||
class Meta:
|
|
||||||
model = Playlist
|
|
||||||
fields = ()
|
|
|
@ -2,40 +2,37 @@
|
||||||
from rest_framework import serializers
|
from rest_framework import serializers
|
||||||
|
|
||||||
from akarpov.common.api.serializers import SetUserModelSerializer
|
from akarpov.common.api.serializers import SetUserModelSerializer
|
||||||
from akarpov.music.models import (
|
from akarpov.music.models import Album, Author, Playlist, Song
|
||||||
Album,
|
|
||||||
Author,
|
|
||||||
Playlist,
|
|
||||||
PlaylistSong,
|
|
||||||
Song,
|
|
||||||
SongUserRating,
|
|
||||||
)
|
|
||||||
from akarpov.users.api.serializers import UserPublicInfoSerializer
|
from akarpov.users.api.serializers import UserPublicInfoSerializer
|
||||||
|
|
||||||
|
|
||||||
class AuthorSerializer(serializers.ModelSerializer):
|
class AuthorSerializer(serializers.ModelSerializer):
|
||||||
|
url = serializers.SerializerMethodField(method_name="get_url")
|
||||||
|
|
||||||
|
@extend_schema_field(serializers.URLField)
|
||||||
|
def get_url(self, obj):
|
||||||
|
return obj.get_absolute_url()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Author
|
model = Author
|
||||||
fields = ["name", "slug", "link", "image_cropped"]
|
fields = ["name", "link", "image_cropped", "url"]
|
||||||
|
|
||||||
|
|
||||||
class AlbumSerializer(serializers.ModelSerializer):
|
class AlbumSerializer(serializers.ModelSerializer):
|
||||||
|
url = serializers.SerializerMethodField(method_name="get_url")
|
||||||
|
|
||||||
|
@extend_schema_field(serializers.URLField)
|
||||||
|
def get_url(self, obj):
|
||||||
|
return obj.get_absolute_url()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Album
|
model = Album
|
||||||
fields = ["name", "slug", "link", "image_cropped"]
|
fields = ["name", "link", "image_cropped", "url"]
|
||||||
|
|
||||||
|
|
||||||
class SongSerializer(serializers.ModelSerializer):
|
class SongSerializer(serializers.ModelSerializer):
|
||||||
authors = AuthorSerializer(many=True)
|
authors = AuthorSerializer(many=True)
|
||||||
album = AlbumSerializer()
|
album = AlbumSerializer()
|
||||||
liked = serializers.SerializerMethodField(method_name="get_liked")
|
|
||||||
|
|
||||||
@extend_schema_field(serializers.BooleanField)
|
|
||||||
def get_liked(self, obj):
|
|
||||||
if self.context["request"].user.is_authenticated:
|
|
||||||
return SongUserRating.objects.filter(
|
|
||||||
song=obj, user=self.context["request"].user, like=True
|
|
||||||
).exists()
|
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Song
|
model = Song
|
||||||
|
@ -48,7 +45,6 @@ class Meta:
|
||||||
"file",
|
"file",
|
||||||
"authors",
|
"authors",
|
||||||
"album",
|
"album",
|
||||||
"liked",
|
|
||||||
]
|
]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
"slug": {"read_only": True},
|
"slug": {"read_only": True},
|
||||||
|
@ -62,15 +58,12 @@ class ListSongSerializer(SetUserModelSerializer):
|
||||||
album = serializers.CharField(source="album.name", read_only=True)
|
album = serializers.CharField(source="album.name", read_only=True)
|
||||||
liked = serializers.SerializerMethodField(method_name="get_liked")
|
liked = serializers.SerializerMethodField(method_name="get_liked")
|
||||||
|
|
||||||
@extend_schema_field(serializers.BooleanField)
|
|
||||||
def get_liked(self, obj):
|
def get_liked(self, obj):
|
||||||
if "likes" in self.context:
|
|
||||||
return self.context["likes"]
|
|
||||||
return obj.id in self.context["likes_ids"]
|
return obj.id in self.context["likes_ids"]
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Song
|
model = Song
|
||||||
fields = ["name", "slug", "file", "image_cropped", "length", "album", "liked"]
|
fields = ["name", "slug", "file", "image_cropped", "length", "album"]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
"slug": {"read_only": True},
|
"slug": {"read_only": True},
|
||||||
"image_cropped": {"read_only": True},
|
"image_cropped": {"read_only": True},
|
||||||
|
@ -80,15 +73,14 @@ class Meta:
|
||||||
|
|
||||||
|
|
||||||
class PlaylistSerializer(SetUserModelSerializer):
|
class PlaylistSerializer(SetUserModelSerializer):
|
||||||
creator = UserPublicInfoSerializer(read_only=True)
|
creator = UserPublicInfoSerializer()
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = Playlist
|
model = Playlist
|
||||||
fields = ["name", "length", "slug", "private", "creator"]
|
fields = ["name", "slug", "private", "creator"]
|
||||||
extra_kwargs = {
|
extra_kwargs = {
|
||||||
"slug": {"read_only": True},
|
"slug": {"read_only": True},
|
||||||
"creator": {"read_only": True},
|
"creator": {"read_only": True},
|
||||||
"length": {"read_only": True},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -103,131 +95,3 @@ class Meta:
|
||||||
"slug": {"read_only": True},
|
"slug": {"read_only": True},
|
||||||
"creator": {"read_only": True},
|
"creator": {"read_only": True},
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class AddSongToPlaylistSerializer(serializers.ModelSerializer):
|
|
||||||
song = serializers.SlugField()
|
|
||||||
playlist = serializers.SlugField()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Playlist
|
|
||||||
fields = ["song", "playlist"]
|
|
||||||
extra_kwargs = {
|
|
||||||
"song": {"write_only": True},
|
|
||||||
"playlist": {"write_only": True},
|
|
||||||
}
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
if not Playlist.objects.filter(slug=attrs["playlist"]).exists():
|
|
||||||
raise serializers.ValidationError("Playlist not found")
|
|
||||||
if not Song.objects.filter(slug=attrs["song"]).exists():
|
|
||||||
raise serializers.ValidationError("Song not found")
|
|
||||||
if self.context["create"]:
|
|
||||||
if PlaylistSong.objects.filter(
|
|
||||||
playlist__slug=attrs["playlist"], song__slug=attrs["song"]
|
|
||||||
).exists():
|
|
||||||
raise serializers.ValidationError("Song already in playlist")
|
|
||||||
else:
|
|
||||||
if not PlaylistSong.objects.filter(
|
|
||||||
playlist__slug=attrs["playlist"], song__slug=attrs["song"]
|
|
||||||
).exists():
|
|
||||||
raise serializers.ValidationError("Song not in playlist")
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
playlist = Playlist.objects.get(slug=validated_data["playlist"])
|
|
||||||
song = Song.objects.get(slug=validated_data["song"])
|
|
||||||
if not self.context["create"]:
|
|
||||||
playlist_song = PlaylistSong.objects.get(
|
|
||||||
playlist=playlist, song=song
|
|
||||||
).delete()
|
|
||||||
else:
|
|
||||||
order = playlist.songs.count()
|
|
||||||
playlist_song = playlist.songs.create(song=song, order=order)
|
|
||||||
return playlist_song
|
|
||||||
|
|
||||||
|
|
||||||
class LikeDislikeSongSerializer(serializers.ModelSerializer):
|
|
||||||
song = serializers.SlugField()
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = SongUserRating
|
|
||||||
fields = ["song"]
|
|
||||||
extra_kwargs = {
|
|
||||||
"song": {"write_only": True},
|
|
||||||
}
|
|
||||||
|
|
||||||
def validate(self, attrs):
|
|
||||||
if not Song.objects.filter(slug=attrs["song"]).exists():
|
|
||||||
raise serializers.ValidationError("Song not found")
|
|
||||||
return attrs
|
|
||||||
|
|
||||||
def create(self, validated_data):
|
|
||||||
song = Song.objects.get(slug=validated_data["song"])
|
|
||||||
if self.context["like"]:
|
|
||||||
if SongUserRating.objects.filter(
|
|
||||||
song=song, user=self.context["request"].user
|
|
||||||
).exists():
|
|
||||||
song_user_rating = SongUserRating.objects.get(
|
|
||||||
song=song, user=self.context["request"].user
|
|
||||||
)
|
|
||||||
if song_user_rating.like:
|
|
||||||
song_user_rating.delete()
|
|
||||||
else:
|
|
||||||
song_user_rating.like = True
|
|
||||||
song_user_rating.save()
|
|
||||||
else:
|
|
||||||
song_user_rating = SongUserRating.objects.create(
|
|
||||||
song=song, user=self.context["request"].user, like=True
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
if SongUserRating.objects.filter(
|
|
||||||
song=song, user=self.context["request"].user
|
|
||||||
).exists():
|
|
||||||
song_user_rating = SongUserRating.objects.get(
|
|
||||||
song=song, user=self.context["request"].user
|
|
||||||
)
|
|
||||||
if not song_user_rating.like:
|
|
||||||
song_user_rating.delete()
|
|
||||||
else:
|
|
||||||
song_user_rating.like = False
|
|
||||||
song_user_rating.save()
|
|
||||||
else:
|
|
||||||
song_user_rating = SongUserRating.objects.create(
|
|
||||||
song=song, user=self.context["request"].user, like=False
|
|
||||||
)
|
|
||||||
return song_user_rating
|
|
||||||
|
|
||||||
|
|
||||||
class ListPlaylistSerializer(serializers.ModelSerializer):
|
|
||||||
class Meta:
|
|
||||||
model = Playlist
|
|
||||||
fields = ["name", "slug", "private"]
|
|
||||||
extra_kwargs = {
|
|
||||||
"slug": {"read_only": True},
|
|
||||||
"private": {"read_only": True},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class FullAlbumSerializer(serializers.ModelSerializer):
|
|
||||||
songs = ListSongSerializer(many=True, read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Album
|
|
||||||
fields = ["name", "link", "image", "songs"]
|
|
||||||
extra_kwargs = {
|
|
||||||
"link": {"read_only": True},
|
|
||||||
"image": {"read_only": True},
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
class FullAuthorSerializer(serializers.ModelSerializer):
|
|
||||||
songs = ListSongSerializer(many=True, read_only=True)
|
|
||||||
|
|
||||||
class Meta:
|
|
||||||
model = Author
|
|
||||||
fields = ["name", "link", "image", "songs"]
|
|
||||||
extra_kwargs = {
|
|
||||||
"link": {"read_only": True},
|
|
||||||
"image": {"read_only": True},
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,19 +1,8 @@
|
||||||
from django.urls import path
|
from django.urls import path
|
||||||
|
|
||||||
from akarpov.music.api.views import (
|
from akarpov.music.api.views import (
|
||||||
AddSongToPlaylistAPIView,
|
|
||||||
DislikeSongAPIView,
|
|
||||||
LikeSongAPIView,
|
|
||||||
ListAlbumsAPIView,
|
|
||||||
ListAuthorsAPIView,
|
|
||||||
ListCreatePlaylistAPIView,
|
ListCreatePlaylistAPIView,
|
||||||
ListCreateSongAPIView,
|
ListCreateSongAPIView,
|
||||||
ListDislikedSongsAPIView,
|
|
||||||
ListLikedSongsAPIView,
|
|
||||||
ListPublicPlaylistAPIView,
|
|
||||||
RemoveSongFromPlaylistAPIView,
|
|
||||||
RetrieveUpdateDestroyAlbumAPIView,
|
|
||||||
RetrieveUpdateDestroyAuthorAPIView,
|
|
||||||
RetrieveUpdateDestroyPlaylistAPIView,
|
RetrieveUpdateDestroyPlaylistAPIView,
|
||||||
RetrieveUpdateDestroySongAPIView,
|
RetrieveUpdateDestroySongAPIView,
|
||||||
)
|
)
|
||||||
|
@ -21,16 +10,9 @@
|
||||||
app_name = "music"
|
app_name = "music"
|
||||||
|
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
path("song/liked/", ListLikedSongsAPIView.as_view(), name="list_liked"),
|
|
||||||
path("song/disliked/", ListDislikedSongsAPIView.as_view(), name="list_disliked"),
|
|
||||||
path(
|
path(
|
||||||
"playlists/", ListCreatePlaylistAPIView.as_view(), name="list_create_playlist"
|
"playlists/", ListCreatePlaylistAPIView.as_view(), name="list_create_playlist"
|
||||||
),
|
),
|
||||||
path(
|
|
||||||
"playlists/public/",
|
|
||||||
ListPublicPlaylistAPIView.as_view(),
|
|
||||||
name="list_public",
|
|
||||||
),
|
|
||||||
path(
|
path(
|
||||||
"playlists/<str:slug>",
|
"playlists/<str:slug>",
|
||||||
RetrieveUpdateDestroyPlaylistAPIView.as_view(),
|
RetrieveUpdateDestroyPlaylistAPIView.as_view(),
|
||||||
|
@ -42,20 +24,4 @@
|
||||||
RetrieveUpdateDestroySongAPIView.as_view(),
|
RetrieveUpdateDestroySongAPIView.as_view(),
|
||||||
name="retrieve_update_delete_song",
|
name="retrieve_update_delete_song",
|
||||||
),
|
),
|
||||||
path("song/like/", LikeSongAPIView.as_view()),
|
|
||||||
path("song/dislike/", DislikeSongAPIView.as_view()),
|
|
||||||
path("playlists/add/", AddSongToPlaylistAPIView.as_view()),
|
|
||||||
path("playlists/remove/", RemoveSongFromPlaylistAPIView.as_view()),
|
|
||||||
path("albums/", ListAlbumsAPIView.as_view(), name="list_albums"),
|
|
||||||
path(
|
|
||||||
"albums/<str:slug>",
|
|
||||||
RetrieveUpdateDestroyAlbumAPIView.as_view(),
|
|
||||||
name="retrieve_update_delete_album",
|
|
||||||
),
|
|
||||||
path("authors/", ListAuthorsAPIView.as_view(), name="list_authors"),
|
|
||||||
path(
|
|
||||||
"authors/<str:slug>",
|
|
||||||
RetrieveUpdateDestroyAuthorAPIView.as_view(),
|
|
||||||
name="retrieve_update_delete_author",
|
|
||||||
),
|
|
||||||
]
|
]
|
||||||
|
|
|
@ -3,19 +3,12 @@
|
||||||
from akarpov.common.api.pagination import StandardResultsSetPagination
|
from akarpov.common.api.pagination import StandardResultsSetPagination
|
||||||
from akarpov.common.api.permissions import IsAdminOrReadOnly, IsCreatorOrReadOnly
|
from akarpov.common.api.permissions import IsAdminOrReadOnly, IsCreatorOrReadOnly
|
||||||
from akarpov.music.api.serializers import (
|
from akarpov.music.api.serializers import (
|
||||||
AddSongToPlaylistSerializer,
|
|
||||||
AlbumSerializer,
|
|
||||||
AuthorSerializer,
|
|
||||||
FullAlbumSerializer,
|
|
||||||
FullAuthorSerializer,
|
|
||||||
FullPlaylistSerializer,
|
FullPlaylistSerializer,
|
||||||
LikeDislikeSongSerializer,
|
|
||||||
ListPlaylistSerializer,
|
|
||||||
ListSongSerializer,
|
ListSongSerializer,
|
||||||
PlaylistSerializer,
|
PlaylistSerializer,
|
||||||
SongSerializer,
|
SongSerializer,
|
||||||
)
|
)
|
||||||
from akarpov.music.models import Album, Author, Playlist, Song, SongUserRating
|
from akarpov.music.models import Playlist, Song, SongUserRating
|
||||||
|
|
||||||
|
|
||||||
class LikedSongsContextMixin(generics.GenericAPIView):
|
class LikedSongsContextMixin(generics.GenericAPIView):
|
||||||
|
@ -33,23 +26,11 @@ def get_serializer_context(self):
|
||||||
|
|
||||||
|
|
||||||
class ListCreatePlaylistAPIView(generics.ListCreateAPIView):
|
class ListCreatePlaylistAPIView(generics.ListCreateAPIView):
|
||||||
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
|
permission_classes = [permissions.IsAuthenticated]
|
||||||
serializer_class = PlaylistSerializer
|
serializer_class = PlaylistSerializer
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if self.request.user.is_authenticated:
|
return Playlist.objects.filter(creator=self.request.user)
|
||||||
return Playlist.objects.filter(creator=self.request.user).select_related(
|
|
||||||
"creator"
|
|
||||||
)
|
|
||||||
return Playlist.objects.filter(private=False).select_related("creator")
|
|
||||||
|
|
||||||
|
|
||||||
class ListPublicPlaylistAPIView(generics.ListAPIView):
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
serializer_class = PlaylistSerializer
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Playlist.objects.filter(private=False)
|
|
||||||
|
|
||||||
|
|
||||||
class RetrieveUpdateDestroyPlaylistAPIView(
|
class RetrieveUpdateDestroyPlaylistAPIView(
|
||||||
|
@ -60,11 +41,14 @@ class RetrieveUpdateDestroyPlaylistAPIView(
|
||||||
permission_classes = [IsCreatorOrReadOnly]
|
permission_classes = [IsCreatorOrReadOnly]
|
||||||
serializer_class = FullPlaylistSerializer
|
serializer_class = FullPlaylistSerializer
|
||||||
|
|
||||||
def get_queryset(self):
|
def __init__(self, **kwargs):
|
||||||
qs = Playlist.objects.filter(private=False)
|
super().__init__(**kwargs)
|
||||||
if self.request.user.is_authenticated:
|
self.object = None
|
||||||
qs = Playlist.objects.filter(creator=self.request.user) | qs
|
|
||||||
return qs.select_related("creator")
|
def get_object(self):
|
||||||
|
if not self.object:
|
||||||
|
self.object = super().get_object()
|
||||||
|
return self.object
|
||||||
|
|
||||||
|
|
||||||
class ListCreateSongAPIView(LikedSongsContextMixin, generics.ListCreateAPIView):
|
class ListCreateSongAPIView(LikedSongsContextMixin, generics.ListCreateAPIView):
|
||||||
|
@ -75,11 +59,9 @@ class ListCreateSongAPIView(LikedSongsContextMixin, generics.ListCreateAPIView):
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
if self.request.user.is_authenticated:
|
if self.request.user.is_authenticated:
|
||||||
return (
|
return (
|
||||||
Song.objects.all()
|
Song.objects.exclude(
|
||||||
.exclude(
|
|
||||||
id__in=SongUserRating.objects.filter(
|
id__in=SongUserRating.objects.filter(
|
||||||
user=self.request.user,
|
user=self.request.user
|
||||||
like=False,
|
|
||||||
).values_list("song_id", flat=True)
|
).values_list("song_id", flat=True)
|
||||||
)
|
)
|
||||||
.prefetch_related("authors")
|
.prefetch_related("authors")
|
||||||
|
@ -94,149 +76,29 @@ class RetrieveUpdateDestroySongAPIView(generics.RetrieveUpdateDestroyAPIView):
|
||||||
permission_classes = [IsCreatorOrReadOnly]
|
permission_classes = [IsCreatorOrReadOnly]
|
||||||
serializer_class = SongSerializer
|
serializer_class = SongSerializer
|
||||||
|
|
||||||
def get_queryset(self):
|
def __init__(self, **kwargs):
|
||||||
return Song.objects.all()
|
super().__init__(**kwargs)
|
||||||
|
self.object = None
|
||||||
|
|
||||||
|
def get_object(self):
|
||||||
class ListSongPlaylistsAPIView(generics.ListAPIView):
|
if not self.object:
|
||||||
serializer_class = ListPlaylistSerializer
|
self.object = super().get_object()
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
return self.object
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Playlist.objects.filter(
|
|
||||||
songs__song__slug=self.kwargs["slug"], creator=self.request.user
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class ListLikedSongsAPIView(generics.ListAPIView):
|
class ListLikedSongsAPIView(generics.ListAPIView):
|
||||||
serializer_class = ListSongSerializer
|
serializer_class = ListSongSerializer
|
||||||
pagination_class = StandardResultsSetPagination
|
pagination_class = StandardResultsSetPagination
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
authentication_classes = [permissions.IsAuthenticated]
|
||||||
|
|
||||||
def get_serializer_context(self):
|
|
||||||
context = super().get_serializer_context()
|
|
||||||
context["likes"] = True
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
def get_queryset(self):
|
||||||
return (
|
return (
|
||||||
Song.objects.cache()
|
Song.objects.cache()
|
||||||
.filter(
|
.filter(
|
||||||
id__in=SongUserRating.objects.cache()
|
id__in=self.request.user.song_likes.objects.cache()
|
||||||
.filter(user=self.request.user, like=True)
|
.all()
|
||||||
.values_list("song_id", flat=True)
|
.values_list("song_id", flat=True)
|
||||||
)
|
)
|
||||||
.prefetch_related("authors")
|
.prefetch_related("authors")
|
||||||
.select_related("album")
|
.select_related("album")
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
class ListDislikedSongsAPIView(generics.ListAPIView):
|
|
||||||
serializer_class = ListSongSerializer
|
|
||||||
pagination_class = StandardResultsSetPagination
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_serializer_context(self):
|
|
||||||
context = super().get_serializer_context()
|
|
||||||
context["likes"] = False
|
|
||||||
return context
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return (
|
|
||||||
Song.objects.cache()
|
|
||||||
.filter(
|
|
||||||
id__in=SongUserRating.objects.cache()
|
|
||||||
.filter(user=self.request.user, like=True)
|
|
||||||
.values_list("song_id", flat=False)
|
|
||||||
)
|
|
||||||
.prefetch_related("authors")
|
|
||||||
.select_related("album")
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class AddSongToPlaylistAPIView(generics.CreateAPIView):
|
|
||||||
serializer_class = AddSongToPlaylistSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Playlist.objects.filter(creator=self.request.user)
|
|
||||||
|
|
||||||
def get_serializer_context(self, **kwargs):
|
|
||||||
context = super().get_serializer_context()
|
|
||||||
context["create"] = True
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class RemoveSongFromPlaylistAPIView(generics.DestroyAPIView):
|
|
||||||
serializer_class = AddSongToPlaylistSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Playlist.objects.filter(creator=self.request.user)
|
|
||||||
|
|
||||||
def get_serializer_context(self, **kwargs):
|
|
||||||
context = super().get_serializer_context()
|
|
||||||
context["create"] = False
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class LikeSongAPIView(generics.CreateAPIView):
|
|
||||||
serializer_class = LikeDislikeSongSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return SongUserRating.objects.all()
|
|
||||||
|
|
||||||
def get_serializer_context(self, **kwargs):
|
|
||||||
context = super().get_serializer_context()
|
|
||||||
context["like"] = True
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class DislikeSongAPIView(generics.CreateAPIView):
|
|
||||||
serializer_class = LikeDislikeSongSerializer
|
|
||||||
permission_classes = [permissions.IsAuthenticated]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return SongUserRating.objects.all()
|
|
||||||
|
|
||||||
def get_serializer_context(self, **kwargs):
|
|
||||||
context = super().get_serializer_context()
|
|
||||||
context["like"] = False
|
|
||||||
return context
|
|
||||||
|
|
||||||
|
|
||||||
class ListAlbumsAPIView(generics.ListAPIView):
|
|
||||||
serializer_class = AlbumSerializer
|
|
||||||
pagination_class = StandardResultsSetPagination
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Album.objects.all()
|
|
||||||
|
|
||||||
|
|
||||||
class RetrieveUpdateDestroyAlbumAPIView(
|
|
||||||
LikedSongsContextMixin, generics.RetrieveUpdateDestroyAPIView
|
|
||||||
):
|
|
||||||
lookup_field = "slug"
|
|
||||||
lookup_url_kwarg = "slug"
|
|
||||||
permission_classes = [IsAdminOrReadOnly]
|
|
||||||
serializer_class = FullAlbumSerializer
|
|
||||||
|
|
||||||
|
|
||||||
class ListAuthorsAPIView(generics.ListAPIView):
|
|
||||||
serializer_class = AuthorSerializer
|
|
||||||
pagination_class = StandardResultsSetPagination
|
|
||||||
permission_classes = [permissions.AllowAny]
|
|
||||||
|
|
||||||
def get_queryset(self):
|
|
||||||
return Author.objects.all()
|
|
||||||
|
|
||||||
|
|
||||||
class RetrieveUpdateDestroyAuthorAPIView(
|
|
||||||
LikedSongsContextMixin, generics.RetrieveUpdateDestroyAPIView
|
|
||||||
):
|
|
||||||
lookup_field = "slug"
|
|
||||||
lookup_url_kwarg = "slug"
|
|
||||||
permission_classes = [IsAdminOrReadOnly]
|
|
||||||
serializer_class = FullAuthorSerializer
|
|
||||||
|
|
|
@ -87,14 +87,14 @@ class SlugMeta:
|
||||||
|
|
||||||
class Playlist(ShortLinkModel, UserHistoryModel):
|
class Playlist(ShortLinkModel, UserHistoryModel):
|
||||||
name = models.CharField(max_length=200)
|
name = models.CharField(max_length=200)
|
||||||
private = models.BooleanField(default=True)
|
private = models.BooleanField(default=False)
|
||||||
creator = models.ForeignKey(
|
creator = models.ForeignKey(
|
||||||
"users.User", related_name="playlists", on_delete=models.CASCADE
|
"users.User", related_name="playlists", on_delete=models.CASCADE
|
||||||
)
|
)
|
||||||
length = models.IntegerField(default=0)
|
length = models.IntegerField(default=0)
|
||||||
|
|
||||||
def get_absolute_url(self):
|
def get_absolute_url(self):
|
||||||
return reverse("music:playlist", kwargs={"slug": self.slug})
|
return reverse("playlist:song", kwargs={"slug": self.slug})
|
||||||
|
|
||||||
def get_songs(self):
|
def get_songs(self):
|
||||||
return self.songs.all().values("song")
|
return self.songs.all().values("song")
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
from django.db.models.signals import post_delete, post_save, pre_save
|
from django.db.models.signals import post_delete, post_save, pre_save
|
||||||
from django.dispatch import receiver
|
from django.dispatch import receiver
|
||||||
|
|
||||||
from akarpov.music.models import PlaylistSong, Song, SongUserRating
|
from akarpov.music.models import Song, SongUserRating
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=Song)
|
@receiver(post_delete, sender=Song)
|
||||||
|
@ -34,27 +34,3 @@ def create_or_update_rating(sender, instance: SongUserRating, **kwargs):
|
||||||
else:
|
else:
|
||||||
song.likes -= 1
|
song.likes -= 1
|
||||||
song.save(update_fields=["likes"])
|
song.save(update_fields=["likes"])
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=SongUserRating)
|
|
||||||
def delete_rating(sender, instance: SongUserRating, **kwargs):
|
|
||||||
song = instance.song
|
|
||||||
if instance.like:
|
|
||||||
song.likes -= 1
|
|
||||||
else:
|
|
||||||
song.likes += 1
|
|
||||||
song.save(update_fields=["likes"])
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_save, sender=PlaylistSong)
|
|
||||||
def update_playlist_length(sender, instance: PlaylistSong, **kwargs):
|
|
||||||
playlist = instance.playlist
|
|
||||||
playlist.length = playlist.songs.count()
|
|
||||||
playlist.save(update_fields=["length"])
|
|
||||||
|
|
||||||
|
|
||||||
@receiver(post_delete, sender=PlaylistSong)
|
|
||||||
def update_playlist_length_delete(sender, instance: PlaylistSong, **kwargs):
|
|
||||||
playlist = instance.playlist
|
|
||||||
playlist.length = playlist.songs.count()
|
|
||||||
playlist.save(update_fields=["length"])
|
|
||||||
|
|
|
@ -26,18 +26,6 @@ def get_object_user(obj: Model) -> User | None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
@lru_cache
|
|
||||||
def get_model_user_field(app_name: str, model: str) -> str:
|
|
||||||
model = apps.get_model(app_name, model)
|
|
||||||
if hasattr(model, "creator") and model.creator.field.related_model is User:
|
|
||||||
return "creator"
|
|
||||||
elif hasattr(model, "user") and model.user.field.related_model is User:
|
|
||||||
return "user"
|
|
||||||
elif hasattr(model, "owner") and model.owner.field.related_model is User:
|
|
||||||
return "owner"
|
|
||||||
return ""
|
|
||||||
|
|
||||||
|
|
||||||
@lru_cache
|
@lru_cache
|
||||||
def get_app_verbose_name(app: str) -> str:
|
def get_app_verbose_name(app: str) -> str:
|
||||||
return apps.get_app_config(app).verbose_name
|
return apps.get_app_config(app).verbose_name
|
||||||
|
|
Loading…
Reference in New Issue
Block a user