mirror of
https://github.com/Alexander-D-Karpov/akarpov
synced 2024-11-22 07:26:33 +03:00
updated api, added music endpoints
This commit is contained in:
parent
aff1cc0591
commit
32912620a4
|
@ -1,5 +1,7 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from akarpov.utils.models import get_model_user_field
|
||||
|
||||
|
||||
class RecursiveField(serializers.Serializer):
|
||||
def to_representation(self, value):
|
||||
|
@ -9,6 +11,19 @@ def to_representation(self, value):
|
|||
|
||||
class SetUserModelSerializer(serializers.ModelSerializer):
|
||||
def create(self, validated_data):
|
||||
if self.context["request"].user.is_authenticated:
|
||||
creator = self.context["request"].user
|
||||
obj = self.Meta.model.objects.create(creator=creator, **validated_data)
|
||||
else:
|
||||
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
|
||||
|
|
9
akarpov/music/api/filters.py
Normal file
9
akarpov/music/api/filters.py
Normal file
|
@ -0,0 +1,9 @@
|
|||
from django_filters import rest_framework as filters
|
||||
|
||||
from akarpov.music.models import Playlist
|
||||
|
||||
|
||||
class PlaylistFilter(filters.FilterSet):
|
||||
class Meta:
|
||||
model = Playlist
|
||||
fields = ()
|
|
@ -2,37 +2,40 @@
|
|||
from rest_framework import serializers
|
||||
|
||||
from akarpov.common.api.serializers import SetUserModelSerializer
|
||||
from akarpov.music.models import Album, Author, Playlist, Song
|
||||
from akarpov.music.models import (
|
||||
Album,
|
||||
Author,
|
||||
Playlist,
|
||||
PlaylistSong,
|
||||
Song,
|
||||
SongUserRating,
|
||||
)
|
||||
from akarpov.users.api.serializers import UserPublicInfoSerializer
|
||||
|
||||
|
||||
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:
|
||||
model = Author
|
||||
fields = ["name", "link", "image_cropped", "url"]
|
||||
fields = ["name", "slug", "link", "image_cropped"]
|
||||
|
||||
|
||||
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:
|
||||
model = Album
|
||||
fields = ["name", "link", "image_cropped", "url"]
|
||||
fields = ["name", "slug", "link", "image_cropped"]
|
||||
|
||||
|
||||
class SongSerializer(serializers.ModelSerializer):
|
||||
authors = AuthorSerializer(many=True)
|
||||
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:
|
||||
model = Song
|
||||
|
@ -45,6 +48,7 @@ class Meta:
|
|||
"file",
|
||||
"authors",
|
||||
"album",
|
||||
"liked",
|
||||
]
|
||||
extra_kwargs = {
|
||||
"slug": {"read_only": True},
|
||||
|
@ -58,12 +62,15 @@ class ListSongSerializer(SetUserModelSerializer):
|
|||
album = serializers.CharField(source="album.name", read_only=True)
|
||||
liked = serializers.SerializerMethodField(method_name="get_liked")
|
||||
|
||||
@extend_schema_field(serializers.BooleanField)
|
||||
def get_liked(self, obj):
|
||||
if "likes" in self.context:
|
||||
return self.context["likes"]
|
||||
return obj.id in self.context["likes_ids"]
|
||||
|
||||
class Meta:
|
||||
model = Song
|
||||
fields = ["name", "slug", "file", "image_cropped", "length", "album"]
|
||||
fields = ["name", "slug", "file", "image_cropped", "length", "album", "liked"]
|
||||
extra_kwargs = {
|
||||
"slug": {"read_only": True},
|
||||
"image_cropped": {"read_only": True},
|
||||
|
@ -73,14 +80,15 @@ class Meta:
|
|||
|
||||
|
||||
class PlaylistSerializer(SetUserModelSerializer):
|
||||
creator = UserPublicInfoSerializer()
|
||||
creator = UserPublicInfoSerializer(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = Playlist
|
||||
fields = ["name", "slug", "private", "creator"]
|
||||
fields = ["name", "length", "slug", "private", "creator"]
|
||||
extra_kwargs = {
|
||||
"slug": {"read_only": True},
|
||||
"creator": {"read_only": True},
|
||||
"length": {"read_only": True},
|
||||
}
|
||||
|
||||
|
||||
|
@ -95,3 +103,131 @@ class Meta:
|
|||
"slug": {"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,8 +1,19 @@
|
|||
from django.urls import path
|
||||
|
||||
from akarpov.music.api.views import (
|
||||
AddSongToPlaylistAPIView,
|
||||
DislikeSongAPIView,
|
||||
LikeSongAPIView,
|
||||
ListAlbumsAPIView,
|
||||
ListAuthorsAPIView,
|
||||
ListCreatePlaylistAPIView,
|
||||
ListCreateSongAPIView,
|
||||
ListDislikedSongsAPIView,
|
||||
ListLikedSongsAPIView,
|
||||
ListPublicPlaylistAPIView,
|
||||
RemoveSongFromPlaylistAPIView,
|
||||
RetrieveUpdateDestroyAlbumAPIView,
|
||||
RetrieveUpdateDestroyAuthorAPIView,
|
||||
RetrieveUpdateDestroyPlaylistAPIView,
|
||||
RetrieveUpdateDestroySongAPIView,
|
||||
)
|
||||
|
@ -10,9 +21,16 @@
|
|||
app_name = "music"
|
||||
|
||||
urlpatterns = [
|
||||
path("song/liked/", ListLikedSongsAPIView.as_view(), name="list_liked"),
|
||||
path("song/disliked/", ListDislikedSongsAPIView.as_view(), name="list_disliked"),
|
||||
path(
|
||||
"playlists/", ListCreatePlaylistAPIView.as_view(), name="list_create_playlist"
|
||||
),
|
||||
path(
|
||||
"playlists/public/",
|
||||
ListPublicPlaylistAPIView.as_view(),
|
||||
name="list_public",
|
||||
),
|
||||
path(
|
||||
"playlists/<str:slug>",
|
||||
RetrieveUpdateDestroyPlaylistAPIView.as_view(),
|
||||
|
@ -24,4 +42,20 @@
|
|||
RetrieveUpdateDestroySongAPIView.as_view(),
|
||||
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,12 +3,19 @@
|
|||
from akarpov.common.api.pagination import StandardResultsSetPagination
|
||||
from akarpov.common.api.permissions import IsAdminOrReadOnly, IsCreatorOrReadOnly
|
||||
from akarpov.music.api.serializers import (
|
||||
AddSongToPlaylistSerializer,
|
||||
AlbumSerializer,
|
||||
AuthorSerializer,
|
||||
FullAlbumSerializer,
|
||||
FullAuthorSerializer,
|
||||
FullPlaylistSerializer,
|
||||
LikeDislikeSongSerializer,
|
||||
ListPlaylistSerializer,
|
||||
ListSongSerializer,
|
||||
PlaylistSerializer,
|
||||
SongSerializer,
|
||||
)
|
||||
from akarpov.music.models import Playlist, Song, SongUserRating
|
||||
from akarpov.music.models import Album, Author, Playlist, Song, SongUserRating
|
||||
|
||||
|
||||
class LikedSongsContextMixin(generics.GenericAPIView):
|
||||
|
@ -26,11 +33,23 @@ def get_serializer_context(self):
|
|||
|
||||
|
||||
class ListCreatePlaylistAPIView(generics.ListCreateAPIView):
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
|
||||
serializer_class = PlaylistSerializer
|
||||
|
||||
def get_queryset(self):
|
||||
return Playlist.objects.filter(creator=self.request.user)
|
||||
if self.request.user.is_authenticated:
|
||||
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(
|
||||
|
@ -41,14 +60,11 @@ class RetrieveUpdateDestroyPlaylistAPIView(
|
|||
permission_classes = [IsCreatorOrReadOnly]
|
||||
serializer_class = FullPlaylistSerializer
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.object = None
|
||||
|
||||
def get_object(self):
|
||||
if not self.object:
|
||||
self.object = super().get_object()
|
||||
return self.object
|
||||
def get_queryset(self):
|
||||
qs = Playlist.objects.filter(private=False)
|
||||
if self.request.user.is_authenticated:
|
||||
qs = Playlist.objects.filter(creator=self.request.user) | qs
|
||||
return qs.select_related("creator")
|
||||
|
||||
|
||||
class ListCreateSongAPIView(LikedSongsContextMixin, generics.ListCreateAPIView):
|
||||
|
@ -59,9 +75,11 @@ class ListCreateSongAPIView(LikedSongsContextMixin, generics.ListCreateAPIView):
|
|||
def get_queryset(self):
|
||||
if self.request.user.is_authenticated:
|
||||
return (
|
||||
Song.objects.exclude(
|
||||
Song.objects.all()
|
||||
.exclude(
|
||||
id__in=SongUserRating.objects.filter(
|
||||
user=self.request.user
|
||||
user=self.request.user,
|
||||
like=False,
|
||||
).values_list("song_id", flat=True)
|
||||
)
|
||||
.prefetch_related("authors")
|
||||
|
@ -76,29 +94,149 @@ class RetrieveUpdateDestroySongAPIView(generics.RetrieveUpdateDestroyAPIView):
|
|||
permission_classes = [IsCreatorOrReadOnly]
|
||||
serializer_class = SongSerializer
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super().__init__(**kwargs)
|
||||
self.object = None
|
||||
def get_queryset(self):
|
||||
return Song.objects.all()
|
||||
|
||||
def get_object(self):
|
||||
if not self.object:
|
||||
self.object = super().get_object()
|
||||
return self.object
|
||||
|
||||
class ListSongPlaylistsAPIView(generics.ListAPIView):
|
||||
serializer_class = ListPlaylistSerializer
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
def get_queryset(self):
|
||||
return Playlist.objects.filter(
|
||||
songs__song__slug=self.kwargs["slug"], creator=self.request.user
|
||||
)
|
||||
|
||||
|
||||
class ListLikedSongsAPIView(generics.ListAPIView):
|
||||
serializer_class = ListSongSerializer
|
||||
pagination_class = StandardResultsSetPagination
|
||||
authentication_classes = [permissions.IsAuthenticated]
|
||||
permission_classes = [permissions.IsAuthenticated]
|
||||
|
||||
def get_serializer_context(self):
|
||||
context = super().get_serializer_context()
|
||||
context["likes"] = True
|
||||
return context
|
||||
|
||||
def get_queryset(self):
|
||||
return (
|
||||
Song.objects.cache()
|
||||
.filter(
|
||||
id__in=self.request.user.song_likes.objects.cache()
|
||||
.all()
|
||||
id__in=SongUserRating.objects.cache()
|
||||
.filter(user=self.request.user, like=True)
|
||||
.values_list("song_id", flat=True)
|
||||
)
|
||||
.prefetch_related("authors")
|
||||
.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):
|
||||
name = models.CharField(max_length=200)
|
||||
private = models.BooleanField(default=False)
|
||||
private = models.BooleanField(default=True)
|
||||
creator = models.ForeignKey(
|
||||
"users.User", related_name="playlists", on_delete=models.CASCADE
|
||||
)
|
||||
length = models.IntegerField(default=0)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse("playlist:song", kwargs={"slug": self.slug})
|
||||
return reverse("music:playlist", kwargs={"slug": self.slug})
|
||||
|
||||
def get_songs(self):
|
||||
return self.songs.all().values("song")
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
from django.db.models.signals import post_delete, post_save, pre_save
|
||||
from django.dispatch import receiver
|
||||
|
||||
from akarpov.music.models import Song, SongUserRating
|
||||
from akarpov.music.models import PlaylistSong, Song, SongUserRating
|
||||
|
||||
|
||||
@receiver(post_delete, sender=Song)
|
||||
|
@ -34,3 +34,27 @@ def create_or_update_rating(sender, instance: SongUserRating, **kwargs):
|
|||
else:
|
||||
song.likes -= 1
|
||||
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,6 +26,18 @@ def get_object_user(obj: Model) -> User | 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
|
||||
def get_app_verbose_name(app: str) -> str:
|
||||
return apps.get_app_config(app).verbose_name
|
||||
|
|
Loading…
Reference in New Issue
Block a user