Extra action form

../_images/actions.png

Action Form

Admin Actions in daily usage often require one or more arguments. This extension provides an easy way to display a form to fill in what needs to be passed to the actions. Namely:

  1. Create a form that holds all the fields needed for any action and set action_form on your JumboModelAdmin pointing to that form.

    Caution

    Set any additional field as required = False otherwise all actions that don’t define that will not let the form validate and you’ll get a ConfigurationError

    Fields defined in this action may be used in different actions. A field required in one action may not be needed in another. See below how to obtain this

  2. Configure which fields are needed for any action in action_form.fields_map dict. See example below

  3. Modify change_list.html template to add

    • templatetag to render admin/actions.html (inluded in {jmb.jadmin}result_list)
    • javascript to toggle visibility of the fields

    this step is already done in jmb.jadmin provided template

JumboModelAdmin.action_form

When ModelAdmin has actions enabled, Django creates a form and places it as attribute action_form, thought is not officially documented. This action will hold

  • the selected action
  • the selected ids or select_across boolean to say all records where selected.

Entending and modifying that form we make available any fields defined in it. The selected row will be available as a queryset, as usual.

You can use JumboModelAdmin.get_action_form_instance() to get an already validated form instance

This is used to specify a different form to add extra action fields. To use this you need override class JumboActionForm. It’s a good idea define these forms in admin_forms.py or in admin/forms.py:

from jmb.jadmin import JumboActionForm

class NewsletterActionForm(JumboActionForm):
    customization = forms.CharField(widget=forms.Textarea, required=False)
    mailing_list = forms.ModelChoiceField(
        queryset=MailingList.objects.filter(status=1),
        label=_('Mailing list'),
        required=False,  # IMPORTANT
        # This is automatically added if not specified. Used from JS to toggle extra action fields
        widget=forms.Select(attrs={'id': 'mailing_list', 'class': 'extra_action_field'})
    )
   fields_map = {
       'export_action': ['output_type'],
       'clone': [],  ## not needed for actions that do not require a  field
       'send_newsletter': ['mailing_list', 'customization'],
       'resend_newsletter': ['mailing_list:required'],
    }

While your ModelAdmin can be sort of:

from jmb.jadmin import JumboModelAdmin
from .admin_form import NewsletterActionForm

class NewsletterAdmin(JumboModelAdmin):

    def send_newsletter(self, request, queryset):
        form = self.get_action_form_instance(request)
        if form.cleaned_data['field_name']:
        ...

    action_form = NewsletterActionForm

JumboActionForm.fields_map

A dictionary to specify action and its extra fields to complete operation. As in the example above you can have:

fields_map = {
   'clone': [],
   'export_action': ['output_type'],
   'resend_newsletter': ['mailing_list:required', 'start_time'],
}
  • no extra fields
  • optional fields: output_type and start_time have a default and are not required
  • required fields. Example: send_newsletter: ['mailing_list:required']. When user select send newsletter action is required to specify mailing_list to whom to send newsletter.

New in version 0.9: This field was previously named action_form_fields and was set on ModelAdmin

Default Action Export

If you use export action to export data as it is currently the deafult in jmb.jadmin, we use a fields_map as follows:

fields_map = {
    'export_action': ['output_type'],
}

that you must retain if you want to use that action.

JumboModelAdmin.get_action_form_instance

It’s a handy function that creates the form in the same way django creates it, and returns a validated form.

Display optional fields in popup

It’s possible to have fields to show in a modal. This is particularly usefull when the fields to be compiled are a lot.

You need to setup the template change_list.html to host the form and the needed javascript. follows a possible implementation that is working correctly. Be sure to understand it and change according to your needs:

{% extends "jadmin:admin/change_list.html" %}
{% load result_list admin_static admin_list i18n admin_urls %}


{% block extrahead %}
  {{ block.super }}
  <script>
    $(document).ready(function ($) {
        $('select[name=action]').change(function(e){
            var value = $('select[name=action]').val();
            if (value == 'send_newsletter') {
                $("#actionModal").modal('show');
                $(".actions").appendTo(".modal-body");
                $('.double').hide();
                $('.field_action').hide();
                $('#customization').css('width', '500px'); // a text field named customization
                $('#actionModal').on('hide.bs.modal', function (e) {
                    $(".actions").insertAfter($('input[name=csrfmiddlewaretoken]'));
                    $('.double').show();
                    $('.field_action').show();
                    $('select[name=action]').val('').prop('selected', true).change();
                });
            }
        });
    });
  </script>
{% endblock %}
{% block result_list %}
  {{ block.super }}
    <div class="modal hide" id="actionModal">
        <div class="modal-header">
            <button class="close" data-dismiss="modal">×</button>
            <h3>My super modal action</h3>

        </div>
        <div class="modal-body"></div>
    </div>
{% endblock %}

API

class jmb.jadmin.actions.JumboActionForm(*args, **kwargs)[source]

The default ActionForm with some logic to implement required fields according to selected action.

check_no_required_field()[source]

Check that no field is required other than action. That would make the validation fail. If you need a required field for an action add :required in the declaration in fields_map as documented above

clean()[source]

Check that any required field is defined

fields_map = {}

mapping between action name and fields needed for the action

get_fields_for_action(action=None)[source]

Return a list of field_names for action action Parses fields_map attribute

Parameters:action – action for which field_names are required. If action is None it looks for selected action in self.cleaned_data. If no action is selected it returns an empty list
get_required_fields_for_action(action=None)[source]

Return a list of required field_names for action action Parses fields_map attribute

Parameters:action – action for which field_names are required. If action is None it looks for selected action in self.cleaned_data. If no action is selected it returns an empty list