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 inline_actions.admin import InlineActionsModelAdminMixin
from radio.admin import BaseSongInline
from .models import RadioProfile, SongRequest
class FavoriteInline(admin.TabularInline):
class FavoriteInline(BaseSongInline):
model = RadioProfile.favorites.through
verbose_name = 'favorite'
verbose_name_plural = 'favorites'
extra = 0
class RatingInline(admin.TabularInline):
@ -18,7 +20,7 @@ class RatingInline(admin.TabularInline):
@admin.register(RadioProfile)
class ProfileAdmin(admin.ModelAdmin):
class ProfileAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
# Edit Form display
readonly_fields = ('created_date', 'modified_date')
fieldsets = (
@ -37,6 +39,11 @@ class ProfileAdmin(admin.ModelAdmin):
inlines = [FavoriteInline, RatingInline]
class Media:
css = {
'all': ('css/remove_inline_object_names.css', )
}
@admin.register(SongRequest)
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 .models import Album, Artist, Game, Song, Store
from profiles.exceptions import MakeRequestError
from profiles.models import RadioProfile
from profiles.actions import RequestSongActionMixin, ToggleFavoriteActionsMixin
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
class BaseSongInline(RequestSongActionMixin,
ToggleFavoriteActionsMixin,
InlineActionsMixin,
admin.TabularInline):
# 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 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 = (
'title',
'game',
@ -72,47 +36,77 @@ class SongInline(RequestSongActionMixin,
verbose_name_plural = 'related songs'
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):
return obj.song.title
song = obj
if not isinstance(song, Song):
song = obj.song
return song.title
title.short_description = 'title'
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'
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'
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):
song = obj
if not isinstance(song, Song):
song = obj.song
return obj.song.is_enabled
_is_enabled.boolean = True
def _is_published(self, obj):
song = obj
if not isinstance(song, Song):
song = obj.song
return obj.song.is_published
_is_published.boolean = True
def _is_requestable(self, obj):
song = obj
if not isinstance(song, Song):
song = obj.song
return obj.song.is_requestable
_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)
class AlbumAdmin(InlineActionsModelAdminMixin, admin.ModelAdmin):
# Detail List display
@ -249,6 +243,7 @@ class StoreAdmin(admin.ModelAdmin):
@admin.register(Song)
class SongAdmin(RequestSongActionMixin,
ToggleFavoriteActionsMixin,
InlineActionsModelAdminMixin,
admin.ModelAdmin):
formfield_overrides = {