Add admin actions for adding/removing multiple artists to songs.

This commit is contained in:
Josh Washburne 2018-01-12 16:35:25 -05:00
parent d8379fe198
commit 65fb7d9f15
4 changed files with 182 additions and 10 deletions

View file

@ -1,8 +1,11 @@
from django.contrib import admin
from django.contrib import admin, messages
from django.db import models
from django.forms import TextInput
from django.http import HttpResponseRedirect
from django.shortcuts import render
from django.utils import timezone
from .forms import ArtistFormSet
from .models import Album, Artist, Game, Song
@ -15,8 +18,6 @@ class ArtistInline(admin.TabularInline):
@admin.register(Album)
class AlbumAdmin(admin.ModelAdmin):
ordering = ("sorted_title",)
# Detail List display
list_display = ('title', '_is_enabled', '_is_published')
search_fields = ['title']
@ -50,8 +51,6 @@ class AlbumAdmin(admin.ModelAdmin):
@admin.register(Artist)
class ArtistAdmin(admin.ModelAdmin):
ordering = ("sorted_full_name",)
# Detail List display
list_display = ('first_name',
'alias',
@ -89,8 +88,6 @@ class ArtistAdmin(admin.ModelAdmin):
@admin.register(Game)
class GameAdmin(admin.ModelAdmin):
ordering = ("sorted_title",)
# Detail List display
list_display = ('title', '_is_enabled', '_is_published')
search_fields = ['title']
@ -124,8 +121,6 @@ class GameAdmin(admin.ModelAdmin):
@admin.register(Song)
class SongAdmin(admin.ModelAdmin):
ordering = ("sorted_title",)
formfield_overrides = {
models.TextField: {'widget': TextInput(attrs={'size': 160, })},
}
@ -133,11 +128,12 @@ class SongAdmin(admin.ModelAdmin):
# Detail List display
list_display = ('title',
'game',
'album',
'artist_list',
'_is_enabled',
'_is_published')
search_fields = ['title']
actions = ['publish_items']
actions = ['publish_items', 'add_artists', 'remove_artists']
# Edit Form display
exclude = ('artists',)
@ -177,6 +173,86 @@ class SongAdmin(admin.ModelAdmin):
def artist_list(self, obj):
return ', '.join([a.full_name for a in obj.artists.all()])
def add_artists(self, request, queryset):
artist_formset = None
# If we clicked "Add Artists", then continue. . .
if 'apply' in request.POST:
# Fill the formset with values from the POST request
artist_formset = ArtistFormSet(request.POST)
# Will only returned "cleaned_data" if form is valid
if artist_formset.is_valid():
# remove the empty form data from the list
data = list(filter(None, artist_formset.cleaned_data))
for artist in data:
for song in queryset:
song.artists.add(artist['artist'])
# Return with informative success message and counts
a_count = len(data)
s_count = queryset.count()
a_msg = ('1 artist was',
'{} artists were'.format(a_count))[a_count > 1]
s_msg = ('1 song', '{} songs'.format(s_count))[s_count > 1]
self.message_user(request,
'{} successfully added to {}.'.format(a_msg,
s_msg))
return HttpResponseRedirect(request.get_full_path())
else:
self.message_user(request,
"See below for errors in the form.",
level=messages.ERROR)
# . . .otherwise, create empty formset.
if not artist_formset:
artist_formset = ArtistFormSet()
return render(request,
'admin/add_artists_intermediate.html',
{'songs': queryset, 'artist_formset': artist_formset, })
add_artists.short_description = "Add artists to selected items"
def remove_artists(self, request, queryset):
artist_formset = None
# If we clicked "Remove Artists", then continue. . .
if 'apply' in request.POST:
# Fill the formset with values from the POST request
artist_formset = ArtistFormSet(request.POST)
# Will only returned "cleaned_data" if form is valid
if artist_formset.is_valid():
# remove the empty form data from the list
data = list(filter(None, artist_formset.cleaned_data))
for artist in data:
for song in queryset:
song.artists.remove(artist['artist'])
# Return with informative success message and counts
a_count = len(data)
s_count = queryset.count()
a_msg = ('1 artist was',
'{} artists were'.format(a_count))[a_count > 1]
s_msg = ('1 song', '{} songs'.format(s_count))[s_count > 1]
self.message_user(request,
'{} successfully removed from {}.'.format(a_msg,
s_msg))
return HttpResponseRedirect(request.get_full_path())
else:
self.message_user(request,
"See below for errors in the form.",
level=messages.ERROR)
# . . .otherwise, create empty formset.
if not artist_formset:
artist_formset = ArtistFormSet()
return render(request,
'admin/remove_artists_intermediate.html',
{'songs': queryset, 'artist_formset': artist_formset, })
remove_artists.short_description = "Remove artists from selected items"
def publish_items(self, request, queryset):
rows_updated = queryset.update(published_date=timezone.now())
if rows_updated == 1:

View file

@ -0,0 +1,10 @@
from django.forms import inlineformset_factory
from .models import Song
ArtistFormSet = inlineformset_factory(Song,
Song.artists.through,
fields=('artist',),
can_delete=False,
extra=10,)

View file

@ -0,0 +1,43 @@
{% extends "admin/base_site.html" %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
{{ artist_formset.management_form }}
<table>
<thead>
<tr>
<th colspan="2">
<p>Select up to ten artists to add to the songs below:</p>
</th>
</tr>
</thead>
{% for form in artist_formset %}
{{ form }}
{% endfor %}
</table>
<table>
<thead>
<tr>
<th>
<p>Artists will be added to the following songs:</p>
</th>
</tr>
</thead>
<tbody>
{% for song in songs %}
<tr>
<th>
{{ song }}
<input type="hidden" name="_selected_action" value="{{ song.pk }}" />
</th>
</tr>
{% endfor %}
</tbody>
</table>
<input type="hidden" name="action" value="add_artists" />
<a href="./"><input type="button" name="Cancel" value="Cancel"></a>
<input type="submit" name="apply" value="Add Artists" />
</form>
{% endblock %}

View file

@ -0,0 +1,43 @@
{% extends "admin/base_site.html" %}
{% block content %}
<form action="" method="post">
{% csrf_token %}
{{ artist_formset.management_form }}
<table>
<thead>
<tr>
<th colspan="2">
<p>Select up to ten artists to remove from the songs below:</p>
</th>
</tr>
</thead>
{% for form in artist_formset %}
{{ form }}
{% endfor %}
</table>
<table>
<thead>
<tr>
<th>
<p>Artists will be removed from the following songs:</p>
</th>
</tr>
</thead>
<tbody>
{% for song in songs %}
<tr>
<th>
{{ song }}
<input type="hidden" name="_selected_action" value="{{ song.pk }}" />
</th>
</tr>
{% endfor %}
</tbody>
</table>
<input type="hidden" name="action" value="remove_artists" />
<a href="./"><input type="button" name="Cancel" value="Cancel"></a>
<input type="submit" name="apply" value="Remove Artists" />
</form>
{% endblock %}