Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a complex admin action that requires additional information?

I'm interested in creating an action for the admin interface that requires some additional information beyond the items selected. My example is bulk adding comics to a series. (Yes I know the obvious answer is to create a schema with X-to-X relationships, but bear with me for the sake of a simple example).

In this example, I've created 100 comics. After they're created, I'd like to associate them with a series object that's already been created. To execute this action within the admin, I'd like to select the items then initiate the action. I should then be asked which series object to use (via a popup, intermediate form, etc.).

I've followed the instructions here which claim to accomplish this via an intermediate form. After working with it, I'm not getting any more errors, but the action itself isn't being executed either - the forloop never gets executed. Instead, it returns to the admin list of comics with the message: "No action selected."

my admin.py method:

from django.shortcuts import render_to_response
from django.template import RequestContext
from django.http import HttpResponseRedirect
def addSeries(self, request, queryset):
    form = None
    if 'cancel' in request.POST:
        self.message_user(request, 'Canceled series linking.')
        return
    elif 'link_series' in request.POST:
        form = self.SeriesForm(request.POST)
        if form.is_valid():
            series = form.cleaned_data['series']
            for x in queryset:
                y = Link(series = series, comic = x)
                y.save()
            self.message_user(request, self.categorySuccess.render(Context({'count':queryset.count(), 'series':series})))
            return HttpResponseRedirect(request.get_full_path())
    if not form:
        form = self.SeriesForm(initial={'_selected_action': request.POST.getlist(admin.ACTION_CHECKBOX_NAME)})
    return render_to_response('setSeries.html', {'comics': queryset, 'form': form, 'path':request.get_full_path()}, context_instance=RequestContext(request))
addSeries.short_description = 'Set Series'

My intermediate form setSeries.html:

<!DOCTYPE html>
<html>
    <head>
        <title>Create Series Links</title>
    </head>
    <body>
        <h1>Create Series Links</h1>
        <p>Choose the series for the selected comic(s):</p>
        <form method="post" action="{{ path }}">
            <table>
                {{ form }}
            </table>
            <p>
                <input type="hidden" name="action" value="changeSeries" />
                <input type="submit" name="cancel" value="Cancel" />
                <input type="submit" name="link_series" value="link_series" />
            </p>
        </form>
        <h2>This categorization will affect the following:</h2>
        <ul>
            {% for comic in comics %}
                <li>{{ comic.title }}</li>
            {% endfor %}
        </ul>
    </body>
</html>
like image 321
tjw Avatar asked Aug 31 '10 00:08

tjw


1 Answers

One thing I notice is that your action’s method is “addSeries”, but in the form you’re calling it “changeSeries”.

In your ModelAdmin, you should have a line like this:

actions = ['addSeries']

If that’s the line you have, then you need to change:

<input type="hidden" name="action" value="changeSeries" />

to:

<input type="hidden" name="action" value="addSeries" />

That’s how Django’s admin knows which action was selected. When you have an intermediary form between choosing the action and performing the action, you’ll need to preserve the action name from the select menu on the admin interface.

like image 109
Jerry Stratton Avatar answered Nov 14 '22 08:11

Jerry Stratton