Refactor for inline reqs. Added inline favorites.

This commit is contained in:
Josh W 2020-02-19 15:30:47 -05:00
parent dd55e37686
commit 4e23507363
3 changed files with 130 additions and 67 deletions

View file

@ -0,0 +1,61 @@
from django.contrib import messages
from radio.models import Song
from .exceptions import MakeRequestError
from .models import RadioProfile
class RequestSongActionMixin(object):
'''This allows a song to be requested directly from an admin page.'''
def get_inline_actions(self, request, obj=None):
actions = super().get_inline_actions(request=request, obj=obj)
actions.append('request_song')
return actions
def request_song(self, request, obj, parent_obj=None):
profile = RadioProfile.objects.get(user=request.user)
# This is to get around the M2M 'through' table on Artists
song = obj
if not isinstance(song, Song):
song = obj.song
try:
profile.make_request(song)
except MakeRequestError as e:
return messages.error(
request,
'Unable to request the song: {}'.format(str(e))
)
return messages.success(request, 'Successfully queued song.')
def get_request_song_label(self, obj):
return 'Request Song'
class ToggleFavoriteActionsMixin(object):
'''This allows a song to be [un]favorited directly from the admin page.'''
def get_inline_actions(self, request, obj=None):
actions = super().get_inline_actions(request=request, obj=obj)
actions.append('toggle_favorite')
return actions
def toggle_favorite(self, request, obj, parent_obj=None):
profile = RadioProfile.objects.get(user=request.user)
# This is to get around the M2M 'through' table
song = obj
if not isinstance(song, Song):
song = obj.song
found = profile.favorites.filter(pk=song.pk).exists()
if found:
profile.favorites.remove(song)
else:
profile.favorites.add(song)
status = 'removed from favorites' if found else 'added to favorites'
messages.success(request, 'Song successfully {}.'.format(status))
def get_toggle_favorite_label(self, obj):
return 'Toggle Favorite'

View file

@ -1,13 +1,15 @@
from django.contrib import admin from django.contrib import admin
from inline_actions.admin import InlineActionsModelAdminMixin
from radio.admin import BaseSongInline
from .models import RadioProfile, SongRequest from .models import RadioProfile, SongRequest
class FavoriteInline(admin.TabularInline): class FavoriteInline(BaseSongInline):
model = RadioProfile.favorites.through model = RadioProfile.favorites.through
verbose_name = 'favorite' verbose_name = 'favorite'
verbose_name_plural = 'favorites' verbose_name_plural = 'favorites'
extra = 0
class RatingInline(admin.TabularInline): class RatingInline(admin.TabularInline):
@ -18,7 +20,7 @@ class RatingInline(admin.TabularInline):
@admin.register(RadioProfile) @admin.register(RadioProfile)
class ProfileAdmin(admin.ModelAdmin): class ProfileAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
# Edit Form display # Edit Form display
readonly_fields = ('created_date', 'modified_date') readonly_fields = ('created_date', 'modified_date')
fieldsets = ( fieldsets = (
@ -37,6 +39,11 @@ class ProfileAdmin(admin.ModelAdmin):
inlines = [FavoriteInline, RatingInline] inlines = [FavoriteInline, RatingInline]
class Media:
css = {
'all': ('css/remove_inline_object_names.css', )
}
@admin.register(SongRequest) @admin.register(SongRequest)
class RequestAdmin(admin.ModelAdmin): class RequestAdmin(admin.ModelAdmin):

View file

@ -8,56 +8,20 @@ from inline_actions.admin import (
from .actions import change_items, publish_items, remove_items from .actions import change_items, publish_items, remove_items
from .models import Album, Artist, Game, Song, Store from .models import Album, Artist, Game, Song, Store
from profiles.exceptions import MakeRequestError from profiles.actions import RequestSongActionMixin, ToggleFavoriteActionsMixin
from profiles.models import RadioProfile
class RequestSongActionMixin(object): class BaseSongInline(RequestSongActionMixin,
'''This allows a song to be requested directly from an admin page.''' ToggleFavoriteActionsMixin,
def get_inline_actions(self, request, obj=None): InlineActionsMixin,
actions = super().get_inline_actions(request=request, obj=obj) admin.TabularInline):
actions.append('request_song') # This is VERY hacky and I hate it. I would love to find something
return actions # a little more DRY. There's this:
# https://gist.github.com/cauethenorio/9db40c59cf406bf328fd
# . . .but it seems to be aimed at ModelAdmins, not Inlines. Maybe a
# refactor is in order when I understand the underlying functionality
# down the road.
def request_song(self, request, obj, parent_obj=None):
profile = RadioProfile.objects.get(user=request.user)
# This is to get around the M2M 'through' table on Artists
song = obj
if not isinstance(song, Song):
song = obj.song
try:
profile.make_request(song)
except MakeRequestError as e:
return messages.error(
request,
'Unable to request the song: {}'.format(str(e))
)
return messages.success(request, 'Successfully queued song.')
def get_request_song_label(self, obj):
return 'Request Song'
class ArtistInline(admin.TabularInline):
model = Song.artists.through
verbose_name = 'artist'
verbose_name_plural = 'artists'
extra = 0
class StoreInline(admin.TabularInline):
model = Song.stores.through
verbose_name = 'data store'
verbose_name_plural = 'data stores'
extra = 0
class SongInline(RequestSongActionMixin,
InlineActionsMixin,
admin.TabularInline):
model = Song
readonly_fields = ( readonly_fields = (
'title', 'title',
'game', 'game',
@ -72,47 +36,77 @@ class SongInline(RequestSongActionMixin,
verbose_name_plural = 'related songs' verbose_name_plural = 'related songs'
extra = 0 extra = 0
def artist_list(self, obj):
return ', '.join([a.full_name for a in obj.artists.all()])
class SongArtistInline(SongInline):
model = Song.artists.through
# This is VERY hacky and I hate it. I would love to find something
# a little more DRY. There's this:
# https://gist.github.com/cauethenorio/9db40c59cf406bf328fd
# . . .but it seems to be aimed at ModelAdmins, not Inlines. Maybe a
# refactor is in order when I understand the underlying functionality
# down the road.
def title(self, obj): def title(self, obj):
return obj.song.title song = obj
if not isinstance(song, Song):
song = obj.song
return song.title
title.short_description = 'title' title.short_description = 'title'
def game(self, obj): def game(self, obj):
return obj.song.game song = obj
if not isinstance(song, Song):
song = obj.song
return song.game
game.short_description = 'game' game.short_description = 'game'
def album(self, obj): def album(self, obj):
return obj.song.album song = obj
if not isinstance(song, Song):
song = obj.song
return song.album
album.short_description = 'album' album.short_description = 'album'
def artist_list(self, obj): def artist_list(self, obj):
return ', '.join([a.full_name for a in obj.song.artists.all()]) song = obj
if not isinstance(song, Song):
song = obj.song
return ', '.join([a.full_name for a in song.artists.all()])
def _is_enabled(self, obj): def _is_enabled(self, obj):
song = obj
if not isinstance(song, Song):
song = obj.song
return obj.song.is_enabled return obj.song.is_enabled
_is_enabled.boolean = True _is_enabled.boolean = True
def _is_published(self, obj): def _is_published(self, obj):
song = obj
if not isinstance(song, Song):
song = obj.song
return obj.song.is_published return obj.song.is_published
_is_published.boolean = True _is_published.boolean = True
def _is_requestable(self, obj): def _is_requestable(self, obj):
song = obj
if not isinstance(song, Song):
song = obj.song
return obj.song.is_requestable return obj.song.is_requestable
_is_requestable.boolean = True _is_requestable.boolean = True
class SongInline(BaseSongInline):
model = Song
class SongArtistInline(BaseSongInline):
model = Song.artists.through
class ArtistInline(admin.TabularInline):
model = Song.artists.through
verbose_name = 'artist'
verbose_name_plural = 'artists'
extra = 0
class StoreInline(admin.TabularInline):
model = Song.stores.through
verbose_name = 'data store'
verbose_name_plural = 'data stores'
extra = 0
@admin.register(Album) @admin.register(Album)
class AlbumAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin): class AlbumAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
# Detail List display # Detail List display
@ -249,6 +243,7 @@ class StoreAdmin(admin.ModelAdmin):
@admin.register(Song) @admin.register(Song)
class SongAdmin(RequestSongActionMixin, class SongAdmin(RequestSongActionMixin,
ToggleFavoriteActionsMixin,
InlineActionsModelAdminMixin, InlineActionsModelAdminMixin,
admin.ModelAdmin): admin.ModelAdmin):
formfield_overrides = { formfield_overrides = {