<NME> actions.py
<BEF> from django import forms
from django.core.exceptions import PermissionDenied
from django.core.urlresolvers import reverse
from django.db import router
from django.http import HttpResponse, HttpResponseRedirect
from django.template import loader
from django.template import loader
from django.template.response import TemplateResponse
from django.utils.encoding import force_unicode
from django.utils.safestring import mark_safe
from django.utils.translation import ugettext as _, ungettext
from xadmin.sites import site
from xadmin.util import model_format_dict, get_deleted_objects, model_ngettext
from xadmin.views import BaseAdminPlugin, ListAdminView

from xadmin.plugins.utils import get_context_dict
from xadmin.sites import site
from xadmin.util import model_format_dict, model_ngettext
from xadmin.views import BaseAdminPlugin, ListAdminView
from xadmin.views.base import filter_hook, ModelAdminView


ACTION_CHECKBOX_NAME = '_selected_action'
checkbox = forms.CheckboxInput({'class': 'action-select'}, lambda value: False)


def action_checkbox(obj):
    return checkbox.render(ACTION_CHECKBOX_NAME, force_text(obj.pk))
action_checkbox.short_description = mark_safe(
    '<input type="checkbox" id="action-toggle" />')
class BaseActionView(ModelAdminView):
    action_name = None
    description = None
    icon = 'remove'

    model_perm = 'change'

    icon = 'fa fa-tasks'

    model_perm = 'change'

    @classmethod
    def has_perm(cls, list_view):
        return list_view.get_model_perms()[cls.model_perm]

    def init_action(self, list_view):
        self.list_view = list_view
        self.admin_site = list_view.admin_site

    @filter_hook
    def do_action(self, queryset):
        pass


class DeleteSelectedAction(BaseActionView):

    delete_selected_confirmation_template = None

    model_perm = 'delete'

    @filter_hook
    def delete_models(self, queryset):

    model_perm = 'delete'
    icon = 'fa fa-times'

    @filter_hook
    def delete_models(self, queryset):
        n = queryset.count()
        if n:
            if self.delete_models_batch:
                self.log('delete', _('Batch delete %(count)d %(items)s.') % { "count": n, "items": model_ngettext(self.opts, n) })
                queryset.delete()
            else:
                for obj in queryset:
                    self.log('delete', '', obj)
                    obj.delete()
            self.message_user(_("Successfully deleted %(count)d %(items)s.") % {
                "count": n, "items": model_ngettext(self.opts, n)
            }, 'success')

    @filter_hook
    def do_action(self, queryset):
        # Check that the user has delete permission for the actual model
        if not self.has_delete_permission():
            raise PermissionDenied

        using = router.db_for_write(self.model)

        # Populate deletable_objects, a data structure of all related objects that
        # will also be deleted.
        deletable_objects, model_count, perms_needed, protected = get_deleted_objects(
            queryset, self.opts, self.user, self.admin_site, using)

        # The user has already confirmed the deletion.
        # Do the deletion and return a None to display the change list view again.
        if self.request.POST.get('post'):
            if perms_needed:
                raise PermissionDenied
            self.delete_models(queryset)
            # Return None to display the change list page again.
            return None

        if len(queryset) == 1:
            objects_name = force_text(self.opts.verbose_name)
        else:
            objects_name = force_text(self.opts.verbose_name_plural)

        if perms_needed or protected:
            title = _("Cannot delete %(name)s") % {"name": objects_name}
        else:
            title = _("Are you sure?")

        context = self.get_context()
        context.update({
            "title": title,
            "objects_name": objects_name,
            "deletable_objects": [deletable_objects],
            'queryset': queryset,
            "perms_lacking": perms_needed,
            "protected": protected,
            "opts": self.opts,
            "app_label": self.app_label,
            'action_checkbox_name': ACTION_CHECKBOX_NAME,
        })

        # Display the confirmation page
        return TemplateResponse(self.request, self.delete_selected_confirmation_template or
                                self.get_template_list('views/model_delete_selected_confirm.html'), context)


class ActionPlugin(BaseAdminPlugin):

    # Actions
    actions = []
    actions_selection_counter = True
    global_actions = [DeleteSelectedAction]

    def init_request(self, *args, **kwargs):
        self.actions = self.get_actions()
        return bool(self.actions)

    def get_list_display(self, list_display):
        if self.actions:
            list_display.insert(0, 'action_checkbox')
            self.admin_view.action_checkbox = action_checkbox
        return list_display

    def get_list_display_links(self, list_display_links):
        if self.actions:
            if len(list_display_links) == 1 and list_display_links[0] == 'action_checkbox':
                return list(self.admin_view.list_display[1:2])
        return list_display_links

    def get_context(self, context):
        if self.actions and self.admin_view.result_count:
            av = self.admin_view
            selection_note_all = ungettext('%(total_count)s selected',
                                           'All %(total_count)s selected', av.result_count)

            new_context = {
                'selection_note': _('0 of %(cnt)s selected') % {'cnt': len(av.result_list)},
                'selection_note_all': selection_note_all % {'total_count': av.result_count},
                'action_choices': self.get_action_choices(),
                'actions_selection_counter': self.actions_selection_counter,
            }
            context.update(new_context)
        return context

    def post_response(self, response, *args, **kwargs):
        request = self.admin_view.request
        av = self.admin_view

        # Actions with no confirmation
        if self.actions and 'action' in request.POST:
            action = request.POST['action']

            if action not in self.actions:
                msg = _("Items must be selected in order to perform "
                        "actions on them. No items have been changed.")
                av.message_user(msg)
                    if not select_across:
                        # Perform the action only on the selected objects
                        queryset = av.list_queryset.filter(pk__in=selected)
                    action_view = self.get_model_view(ac, av.model)
                    action_view.init_action(av)
                    response = action_view.do_action(queryset)
                    # Actions may return an HttpResponse, which will be used as the
                    # response from the POST. If not, we'll be a good little HTTP
                    # citizen and redirect back to the changelist page.
                    msg = _("Items must be selected in order to perform "
                            "actions on them. No items have been changed.")
                    av.message_user(msg)
                        return HttpResponseRedirect(request.get_full_path())
        return response

    def get_actions(self):
        if self.actions is None:
            return SortedDict()

    def response_action(self, ac, queryset):
        if isinstance(ac, type) and issubclass(ac, BaseActionView):
            action_view = self.get_model_view(ac, self.admin_view.model)
            action_view.init_action(self.admin_view)
            return action_view.do_action(queryset)
        else:
            return ac(self.admin_view, self.request, queryset)

    def get_actions(self):
        if self.actions is None:
            return OrderedDict()

        actions = [self.get_action(action) for action in self.global_actions]

        for klass in self.admin_view.__class__.mro()[::-1]:
            class_actions = getattr(klass, 'actions', [])
            if not class_actions:
                continue
            actions.extend(
                [self.get_action(action) for action in class_actions])

        # get_action might have returned None, so filter any of those out.
        actions = filter(None, actions)
        if six.PY3:
            actions = list(actions)

        # Convert the actions into a OrderedDict keyed by name.
        actions = OrderedDict([
            (name, (ac, name, desc, icon))
        return choices

    def get_action(self, action):
        if not issubclass(action, BaseActionView) or not action.has_perm(self.admin_view):
            return None
        return action, getattr(action, 'action_name'), getattr(action, 'description'), getattr(action, 'icon')

    # View Methods
    def result_header(self, item, field_name, row):
            func = getattr(self.admin_view.__class__, action)

        else:
            return None

        if hasattr(func, 'short_description'):
            description = func.short_description
        else:
            description = capfirst(action.replace('_', ' '))

        return func, action, description, getattr(func, 'icon', 'tasks')

    # View Methods
    def result_header(self, item, field_name, row):
        if item.attr and field_name == 'action_checkbox':
            item.classes.append("action-checkbox-column")
        return item

    def result_item(self, item, obj, field_name, row):
        if item.field is None and field_name == u'action_checkbox':
            item.classes.append("action-checkbox")
        return item

    # Media
    def get_media(self, media):
        if self.actions and self.admin_view.result_count:
            media = media + self.vendor('xadmin.plugin.actions.js', 'xadmin.plugins.css')
        return media

    # Block Views
    def block_results_bottom(self, context, nodes):
        if self.actions and self.admin_view.result_count:
            nodes.append(loader.render_to_string('xadmin/blocks/model_list.results_bottom.actions.html',
                                                 context=get_context_dict(context)))


site.register_plugin(ActionPlugin, ListAdminView)

<MSG> Support method or func action.

<DFF> @@ -1,6 +1,5 @@
 from django import forms
 from django.core.exceptions import PermissionDenied
-from django.core.urlresolvers import reverse
 from django.db import router
 from django.http import HttpResponse, HttpResponseRedirect
 from django.template import loader
@@ -9,6 +8,7 @@ from django.utils.datastructures import SortedDict
 from django.utils.encoding import force_unicode
 from django.utils.safestring import mark_safe
 from django.utils.translation import ugettext as _, ungettext
+from django.utils.text import capfirst
 from xadmin.sites import site
 from xadmin.util import model_format_dict, get_deleted_objects, model_ngettext
 from xadmin.views import BaseAdminPlugin, ListAdminView
@@ -31,7 +31,7 @@ action_checkbox.is_column = False
 class BaseActionView(ModelAdminView):
     action_name = None
     description = None
-    icon = 'remove'
+    icon = 'tasks'
 
     model_perm = 'change'
 
@@ -57,6 +57,7 @@ class DeleteSelectedAction(BaseActionView):
     delete_selected_confirmation_template = None
 
     model_perm = 'delete'
+    icon = 'remove'
 
     @filter_hook
     def delete_models(self, queryset):
@@ -182,9 +183,7 @@ class ActionPlugin(BaseAdminPlugin):
                     if not select_across:
                         # Perform the action only on the selected objects
                         queryset = av.list_queryset.filter(pk__in=selected)
-                    action_view = self.get_model_view(ac, av.model)
-                    action_view.init_action(av)
-                    response = action_view.do_action(queryset)
+                    response = self.response_action(ac, queryset)
                     # Actions may return an HttpResponse, which will be used as the
                     # response from the POST. If not, we'll be a good little HTTP
                     # citizen and redirect back to the changelist page.
@@ -194,6 +193,14 @@ class ActionPlugin(BaseAdminPlugin):
                         return HttpResponseRedirect(request.get_full_path())
         return response
 
+    def response_action(self, ac, queryset):
+        if isinstance(ac, type) and issubclass(ac, BaseActionView):
+            action_view = self.get_model_view(ac, self.admin_view.model)
+            action_view.init_action(self.admin_view)
+            return action_view.do_action(queryset)
+        else:
+            return ac(self.admin_view, self.request, queryset)
+
     def get_actions(self):
         if self.actions is None:
             return SortedDict()
@@ -230,9 +237,27 @@ class ActionPlugin(BaseAdminPlugin):
         return choices
 
     def get_action(self, action):
-        if not issubclass(action, BaseActionView) or not action.has_perm(self.admin_view):
+        if isinstance(action, type) and issubclass(action, BaseActionView):
+            if not action.has_perm(self.admin_view):
+                return None
+            return action, getattr(action, 'action_name'), getattr(action, 'description'), getattr(action, 'icon')
+
+        elif callable(action):
+            func = action
+            action = action.__name__
+
+        elif hasattr(self.admin_view.__class__, action):
+            func = getattr(self.admin_view.__class__, action)
+
+        else:
             return None
-        return action, getattr(action, 'action_name'), getattr(action, 'description'), getattr(action, 'icon')
+
+        if hasattr(func, 'short_description'):
+            description = func.short_description
+        else:
+            description = capfirst(action.replace('_', ' '))
+
+        return func, action, description, getattr(func, 'icon', 'tasks')
 
     # View Methods
     def result_header(self, item, field_name, row):

{'commit': "diff --git a/xadmin/plugins/actions.py b/xadmin/plugins/actions.py\nindex 1adead97..b7d3b339 100644\n--- a/xadmin/plugins/actions.py\n+++ b/xadmin/plugins/actions.py\n@@ -1,6 +1,5 @@\n from django import forms\n from django.core.exceptions import PermissionDenied\n-from django.core.urlresolvers import reverse\n from django.db import router\n from django.http import HttpResponse, HttpResponseRedirect\n from django.template import loader\n@@ -9,6 +8,7 @@ from django.utils.datastructures import SortedDict\n from django.utils.encoding import force_unicode\n from django.utils.safestring import mark_safe\n from django.utils.translation import ugettext as _, ungettext\n+from django.utils.text import capfirst\n from xadmin.sites import site\n from xadmin.util import model_format_dict, get_deleted_objects, model_ngettext\n from xadmin.views import BaseAdminPlugin, ListAdminView\n@@ -31,7 +31,7 @@ action_checkbox.is_column = False\n class BaseActionView(ModelAdminView):\n     action_name = None\n     description = None\n-    icon = 'remove'\n+    icon = 'tasks'\n \n     model_perm = 'change'\n \n@@ -57,6 +57,7 @@ class DeleteSelectedAction(BaseActionView):\n     delete_selected_confirmation_template = None\n \n     model_perm = 'delete'\n+    icon = 'remove'\n \n     @filter_hook\n     def delete_models(self, queryset):\n@@ -182,9 +183,7 @@ class ActionPlugin(BaseAdminPlugin):\n                     if not select_across:\n                         # Perform the action only on the selected objects\n                         queryset = av.list_queryset.filter(pk__in=selected)\n-                    action_view = self.get_model_view(ac, av.model)\n-                    action_view.init_action(av)\n-                    response = action_view.do_action(queryset)\n+                    response = self.response_action(ac, queryset)\n                     # Actions may return an HttpResponse, which will be used as the\n                     # response from the POST. If not, we'll be a good little HTTP\n                     # citizen and redirect back to the changelist page.\n@@ -194,6 +193,14 @@ class ActionPlugin(BaseAdminPlugin):\n                         return HttpResponseRedirect(request.get_full_path())\n         return response\n \n+    def response_action(self, ac, queryset):\n+        if isinstance(ac, type) and issubclass(ac, BaseActionView):\n+            action_view = self.get_model_view(ac, self.admin_view.model)\n+            action_view.init_action(self.admin_view)\n+            return action_view.do_action(queryset)\n+        else:\n+            return ac(self.admin_view, self.request, queryset)\n+\n     def get_actions(self):\n         if self.actions is None:\n             return SortedDict()\n@@ -230,9 +237,27 @@ class ActionPlugin(BaseAdminPlugin):\n         return choices\n \n     def get_action(self, action):\n-        if not issubclass(action, BaseActionView) or not action.has_perm(self.admin_view):\n+        if isinstance(action, type) and issubclass(action, BaseActionView):\n+            if not action.has_perm(self.admin_view):\n+                return None\n+            return action, getattr(action, 'action_name'), getattr(action, 'description'), getattr(action, 'icon')\n+\n+        elif callable(action):\n+            func = action\n+            action = action.__name__\n+\n+        elif hasattr(self.admin_view.__class__, action):\n+            func = getattr(self.admin_view.__class__, action)\n+\n+        else:\n             return None\n-        return action, getattr(action, 'action_name'), getattr(action, 'description'), getattr(action, 'icon')\n+\n+        if hasattr(func, 'short_description'):\n+            description = func.short_description\n+        else:\n+            description = capfirst(action.replace('_', ' '))\n+\n+        return func, action, description, getattr(func, 'icon', 'tasks')\n \n     # View Methods\n     def result_header(self, item, field_name, row):\n", 'commit_subject': 'Support method or func action.', 'repo_name': 'sshwsfc/xadmin', 'committer': {'name': 'sshwsfc', 'email': '650a25124d6e016e31624d475d697e231931ae31@gmail.com', 'time_sec': '1378193990', 'tz_offset': '480', 'date': {'seconds': '1378193990'}}, 'commit_tree': '0c64c95817bb2c5a79bd3d0d5520f2bf62ece86e', 'commit_message': 'Support method or func action.\n', 'language_name': 'JavaScript', 'license': 'bsd-3-clause', 'hunks': "@@ -1,6 +1,5 @@\n from django import forms\n from django.core.exceptions import PermissionDenied\n-from django.core.urlresolvers import reverse\n from django.db import router\n from django.http import HttpResponse, HttpResponseRedirect\n from django.template import loader\n@@ -9,6 +8,7 @@ from django.utils.datastructures import SortedDict\n from django.utils.encoding import force_unicode\n from django.utils.safestring import mark_safe\n from django.utils.translation import ugettext as _, ungettext\n+from django.utils.text import capfirst\n from xadmin.sites import site\n from xadmin.util import model_format_dict, get_deleted_objects, model_ngettext\n from xadmin.views import BaseAdminPlugin, ListAdminView\n@@ -31,7 +31,7 @@ action_checkbox.is_column = False\n class BaseActionView(ModelAdminView):\n     action_name = None\n     description = None\n-    icon = 'remove'\n+    icon = 'tasks'\n \n     model_perm = 'change'\n \n@@ -57,6 +57,7 @@ class DeleteSelectedAction(BaseActionView):\n     delete_selected_confirmation_template = None\n \n     model_perm = 'delete'\n+    icon = 'remove'\n \n     @filter_hook\n     def delete_models(self, queryset):\n@@ -182,9 +183,7 @@ class ActionPlugin(BaseAdminPlugin):\n                     if not select_across:\n                         # Perform the action only on the selected objects\n                         queryset = av.list_queryset.filter(pk__in=selected)\n-                    action_view = self.get_model_view(ac, av.model)\n-                    action_view.init_action(av)\n-                    response = action_view.do_action(queryset)\n+                    response = self.response_action(ac, queryset)\n                     # Actions may return an HttpResponse, which will be used as the\n                     # response from the POST. If not, we'll be a good little HTTP\n                     # citizen and redirect back to the changelist page.\n@@ -194,6 +193,14 @@ class ActionPlugin(BaseAdminPlugin):\n                         return HttpResponseRedirect(request.get_full_path())\n         return response\n \n+    def response_action(self, ac, queryset):\n+        if isinstance(ac, type) and issubclass(ac, BaseActionView):\n+            action_view = self.get_model_view(ac, self.admin_view.model)\n+            action_view.init_action(self.admin_view)\n+            return action_view.do_action(queryset)\n+        else:\n+            return ac(self.admin_view, self.request, queryset)\n+\n     def get_actions(self):\n         if self.actions is None:\n             return SortedDict()\n@@ -230,9 +237,27 @@ class ActionPlugin(BaseAdminPlugin):\n         return choices\n \n     def get_action(self, action):\n-        if not issubclass(action, BaseActionView) or not action.has_perm(self.admin_view):\n+        if isinstance(action, type) and issubclass(action, BaseActionView):\n+            if not action.has_perm(self.admin_view):\n+                return None\n+            return action, getattr(action, 'action_name'), getattr(action, 'description'), getattr(action, 'icon')\n+\n+        elif callable(action):\n+            func = action\n+            action = action.__name__\n+\n+        elif hasattr(self.admin_view.__class__, action):\n+            func = getattr(self.admin_view.__class__, action)\n+\n+        else:\n             return None\n-        return action, getattr(action, 'action_name'), getattr(action, 'description'), getattr(action, 'icon')\n+\n+        if hasattr(func, 'short_description'):\n+            description = func.short_description\n+        else:\n+            description = capfirst(action.replace('_', ' '))\n+\n+        return func, action, description, getattr(func, 'icon', 'tasks')\n \n     # View Methods\n     def result_header(self, item, field_name, row):\n", 'addition_count': 32, 'deletion_count': 7, 'src_file': 'a/xadmin/plugins/actions.py', 'tgt_file': 'b/xadmin/plugins/actions.py', 'file_extension': '.py', 'before_file': 'from django import forms\nfrom django.core.exceptions import PermissionDenied\nfrom django.core.urlresolvers import reverse\nfrom django.db import router\nfrom django.http import HttpResponse, HttpResponseRedirect\nfrom django.template import loader\nfrom django.template import loader\nfrom django.template.response import TemplateResponse\nfrom django.utils.encoding import force_unicode\nfrom django.utils.safestring import mark_safe\nfrom django.utils.translation import ugettext as _, ungettext\nfrom xadmin.sites import site\nfrom xadmin.util import model_format_dict, get_deleted_objects, model_ngettext\nfrom xadmin.views import BaseAdminPlugin, ListAdminView\n\nfrom xadmin.plugins.utils import get_context_dict\nfrom xadmin.sites import site\nfrom xadmin.util import model_format_dict, model_ngettext\nfrom xadmin.views import BaseAdminPlugin, ListAdminView\nfrom xadmin.views.base import filter_hook, ModelAdminView\n\n\nACTION_CHECKBOX_NAME = \'_selected_action\'\ncheckbox = forms.CheckboxInput({\'class\': \'action-select\'}, lambda value: False)\n\n\ndef action_checkbox(obj):\n    return checkbox.render(ACTION_CHECKBOX_NAME, force_text(obj.pk))\naction_checkbox.short_description = mark_safe(\n    \'<input type="checkbox" id="action-toggle" />\')\nclass BaseActionView(ModelAdminView):\n    action_name = None\n    description = None\n    icon = \'remove\'\n\n    model_perm = \'change\'\n\n    icon = \'fa fa-tasks\'\n\n    model_perm = \'change\'\n\n    @classmethod\n    def has_perm(cls, list_view):\n        return list_view.get_model_perms()[cls.model_perm]\n\n    def init_action(self, list_view):\n        self.list_view = list_view\n        self.admin_site = list_view.admin_site\n\n    @filter_hook\n    def do_action(self, queryset):\n        pass\n\n\nclass DeleteSelectedAction(BaseActionView):\n\n    delete_selected_confirmation_template = None\n\n    model_perm = \'delete\'\n\n    @filter_hook\n    def delete_models(self, queryset):\n\n    model_perm = \'delete\'\n    icon = \'fa fa-times\'\n\n    @filter_hook\n    def delete_models(self, queryset):\n        n = queryset.count()\n        if n:\n            if self.delete_models_batch:\n                self.log(\'delete\', _(\'Batch delete %(count)d %(items)s.\') % { "count": n, "items": model_ngettext(self.opts, n) })\n                queryset.delete()\n            else:\n                for obj in queryset:\n                    self.log(\'delete\', \'\', obj)\n                    obj.delete()\n            self.message_user(_("Successfully deleted %(count)d %(items)s.") % {\n                "count": n, "items": model_ngettext(self.opts, n)\n            }, \'success\')\n\n    @filter_hook\n    def do_action(self, queryset):\n        # Check that the user has delete permission for the actual model\n        if not self.has_delete_permission():\n            raise PermissionDenied\n\n        using = router.db_for_write(self.model)\n\n        # Populate deletable_objects, a data structure of all related objects that\n        # will also be deleted.\n        deletable_objects, model_count, perms_needed, protected = get_deleted_objects(\n            queryset, self.opts, self.user, self.admin_site, using)\n\n        # The user has already confirmed the deletion.\n        # Do the deletion and return a None to display the change list view again.\n        if self.request.POST.get(\'post\'):\n            if perms_needed:\n                raise PermissionDenied\n            self.delete_models(queryset)\n            # Return None to display the change list page again.\n            return None\n\n        if len(queryset) == 1:\n            objects_name = force_text(self.opts.verbose_name)\n        else:\n            objects_name = force_text(self.opts.verbose_name_plural)\n\n        if perms_needed or protected:\n            title = _("Cannot delete %(name)s") % {"name": objects_name}\n        else:\n            title = _("Are you sure?")\n\n        context = self.get_context()\n        context.update({\n            "title": title,\n            "objects_name": objects_name,\n            "deletable_objects": [deletable_objects],\n            \'queryset\': queryset,\n            "perms_lacking": perms_needed,\n            "protected": protected,\n            "opts": self.opts,\n            "app_label": self.app_label,\n            \'action_checkbox_name\': ACTION_CHECKBOX_NAME,\n        })\n\n        # Display the confirmation page\n        return TemplateResponse(self.request, self.delete_selected_confirmation_template or\n                                self.get_template_list(\'views/model_delete_selected_confirm.html\'), context)\n\n\nclass ActionPlugin(BaseAdminPlugin):\n\n    # Actions\n    actions = []\n    actions_selection_counter = True\n    global_actions = [DeleteSelectedAction]\n\n    def init_request(self, *args, **kwargs):\n        self.actions = self.get_actions()\n        return bool(self.actions)\n\n    def get_list_display(self, list_display):\n        if self.actions:\n            list_display.insert(0, \'action_checkbox\')\n            self.admin_view.action_checkbox = action_checkbox\n        return list_display\n\n    def get_list_display_links(self, list_display_links):\n        if self.actions:\n            if len(list_display_links) == 1 and list_display_links[0] == \'action_checkbox\':\n                return list(self.admin_view.list_display[1:2])\n        return list_display_links\n\n    def get_context(self, context):\n        if self.actions and self.admin_view.result_count:\n            av = self.admin_view\n            selection_note_all = ungettext(\'%(total_count)s selected\',\n                                           \'All %(total_count)s selected\', av.result_count)\n\n            new_context = {\n                \'selection_note\': _(\'0 of %(cnt)s selected\') % {\'cnt\': len(av.result_list)},\n                \'selection_note_all\': selection_note_all % {\'total_count\': av.result_count},\n                \'action_choices\': self.get_action_choices(),\n                \'actions_selection_counter\': self.actions_selection_counter,\n            }\n            context.update(new_context)\n        return context\n\n    def post_response(self, response, *args, **kwargs):\n        request = self.admin_view.request\n        av = self.admin_view\n\n        # Actions with no confirmation\n        if self.actions and \'action\' in request.POST:\n            action = request.POST[\'action\']\n\n            if action not in self.actions:\n                msg = _("Items must be selected in order to perform "\n                        "actions on them. No items have been changed.")\n                av.message_user(msg)\n                    if not select_across:\n                        # Perform the action only on the selected objects\n                        queryset = av.list_queryset.filter(pk__in=selected)\n                    action_view = self.get_model_view(ac, av.model)\n                    action_view.init_action(av)\n                    response = action_view.do_action(queryset)\n                    # Actions may return an HttpResponse, which will be used as the\n                    # response from the POST. If not, we\'ll be a good little HTTP\n                    # citizen and redirect back to the changelist page.\n                    msg = _("Items must be selected in order to perform "\n                            "actions on them. No items have been changed.")\n                    av.message_user(msg)\n                        return HttpResponseRedirect(request.get_full_path())\n        return response\n\n    def get_actions(self):\n        if self.actions is None:\n            return SortedDict()\n\n    def response_action(self, ac, queryset):\n        if isinstance(ac, type) and issubclass(ac, BaseActionView):\n            action_view = self.get_model_view(ac, self.admin_view.model)\n            action_view.init_action(self.admin_view)\n            return action_view.do_action(queryset)\n        else:\n            return ac(self.admin_view, self.request, queryset)\n\n    def get_actions(self):\n        if self.actions is None:\n            return OrderedDict()\n\n        actions = [self.get_action(action) for action in self.global_actions]\n\n        for klass in self.admin_view.__class__.mro()[::-1]:\n            class_actions = getattr(klass, \'actions\', [])\n            if not class_actions:\n                continue\n            actions.extend(\n                [self.get_action(action) for action in class_actions])\n\n        # get_action might have returned None, so filter any of those out.\n        actions = filter(None, actions)\n        if six.PY3:\n            actions = list(actions)\n\n        # Convert the actions into a OrderedDict keyed by name.\n        actions = OrderedDict([\n            (name, (ac, name, desc, icon))\n        return choices\n\n    def get_action(self, action):\n        if not issubclass(action, BaseActionView) or not action.has_perm(self.admin_view):\n            return None\n        return action, getattr(action, \'action_name\'), getattr(action, \'description\'), getattr(action, \'icon\')\n\n    # View Methods\n    def result_header(self, item, field_name, row):\n            func = getattr(self.admin_view.__class__, action)\n\n        else:\n            return None\n\n        if hasattr(func, \'short_description\'):\n            description = func.short_description\n        else:\n            description = capfirst(action.replace(\'_\', \' \'))\n\n        return func, action, description, getattr(func, \'icon\', \'tasks\')\n\n    # View Methods\n    def result_header(self, item, field_name, row):\n        if item.attr and field_name == \'action_checkbox\':\n            item.classes.append("action-checkbox-column")\n        return item\n\n    def result_item(self, item, obj, field_name, row):\n        if item.field is None and field_name == u\'action_checkbox\':\n            item.classes.append("action-checkbox")\n        return item\n\n    # Media\n    def get_media(self, media):\n        if self.actions and self.admin_view.result_count:\n            media = media + self.vendor(\'xadmin.plugin.actions.js\', \'xadmin.plugins.css\')\n        return media\n\n    # Block Views\n    def block_results_bottom(self, context, nodes):\n        if self.actions and self.admin_view.result_count:\n            nodes.append(loader.render_to_string(\'xadmin/blocks/model_list.results_bottom.actions.html\',\n                                                 context=get_context_dict(context)))\n\n\nsite.register_plugin(ActionPlugin, ListAdminView)\n', 'message': 'Support method or func action.\n', 'author_name': 'sshwsfc', 'lang': 'py'}