Setting the rotation level of a song is a manager’s job, so it can only be done in the admin interface. When I wrote about the schedule I talked about changing the admin interface to do what I want, and we need a new view to edit songs in rotation. In the rotation admin, I’ve included a function to get the count of songs with a link to the new view, and included it in the list.
list_display = ('rotation', 'max', 'admin_song_count') def admin_song_count(self, obj): return u"%d" % obj.song_set.all().count() admin_song_count.short_description = u"Number of songs" admin_song_count.allow_tags = True
Now that we’ve got an URL, we need to link it to a view.
def get_urls(self): urls = super(RotationAdmin, self).get_urls() my_urls = patterns('', (r'^songs/$', self.admin_site.admin_view(self.changesongs)) ) return my_urls+urls
See that link at the start about the joy of a flexible admin interface. changesongs
is almost straight forward.
def changesongs(self, request): if request.POST: form = RotationSongFormSet(request.POST, queryset=models.Song.objects.filter(rotation__isnull=False).select_related('rotation', 'artist', 'album').order_by('rotation__max', 'added_on')) if form.is_valid(): form.save() return HttpResponseRedirect("../") else: form = RotationSongFormSet(queryset=models.Song.objects.filter(rotation__isnull=False).select_related('rotation', 'artist', 'album').order_by('rotation__max', 'added_on')) context = { "title" : "Move rotation songs", "formset" : form, "opts" : self.model._meta, "app_label" : self.model._meta.app_label, "root_path": self.admin_site.root_path, "has_change_permission" : True, } context_instance = template.RequestContext(request, current_app=self.admin_site.name) return render_to_response("dj_pro/admin/change_rotation_songs.html", context, context_instance)
The only interesting things are the extra entries in context, which are used by the admin templates, and the extra long queryset. Let’s look at it closely: queryset = models.Song.objects.filter (rotation__isnull=False).select_related ('rotation', 'artist', 'album').order_by ('rotation__max', 'added_on')
. We only get songs that have a rotation level, include related info, and order by rotation, and the day it was added. The order will be used by the formset, so all that the template needs is
{% for f in formset.forms %} <tr> <td>{{f.instance.song}}</td> <td>{{f.instance.artist|default:""}}</td> <td>{{f.instance.album}} #{{f.instance.album.location}}</td> <td>{{f.instance.added_on|date:"SHORT_DATE_FORMAT"}} <td>{{f.id}}{{f.rotation}} {% if f.rotation.errors %}{{f.rotation.errors}}{% endif %} </td> <td>{{f.DELETE}}</td> </tr> {% endfor %}
The DELETE field is another thing altogether. Next post.