Selaa lähdekoodia

Add bulk actions documentation

Co-Authored-By: Thibaud Colas <thibaudcolas@gmail.com>
Shohan 3 vuotta sitten
vanhempi
commit
24f987db49
3 muutettua tiedostoa jossa 319 lisäystä ja 1 poistoa
  1. 243 0
      docs/extending/custom_bulk_actions.rst
  2. 1 0
      docs/extending/index.rst
  3. 75 1
      docs/reference/hooks.rst

+ 243 - 0
docs/extending/custom_bulk_actions.rst

@@ -0,0 +1,243 @@
+.. _custom_bulk_actions:
+
+Adding custom bulk actions
+==========================================
+
+This document describes how to add custom bulk actions to different listings.
+
+
+Registering a custom bulk action
+--------------------------------
+
+    .. code-block:: python
+
+        from wagtail.admin.views.bulk_action import BulkAction
+        from wagtail.core import hooks
+
+
+        @hooks.register('register_bulk_action')
+        class CustomDeleteBulkAction(BulkAction):
+            display_name = _("Delete")
+            aria_label = _("Delete objects")
+            action_type = "delete"
+            template_name = "/path/to/confirm_bulk_delete.html"
+            models = [...]
+
+            @classmethod
+            def execute_action(cls, objects, **kwargs):
+                for obj in objects:
+                    do_something(obj)
+                return num_parent_objects, num_child_objects  # return the count of updated objects
+
+The attributes are as follows:
+
+- ``display_name`` - The label that will be displayed on the button in the user interface
+- ``aria_label`` - The ``aria-label`` attribute that will be applied to the button in the user interface
+- ``action_type`` - A unique identifier for the action. Will be required in the url for bulk actions
+- ``template_name`` - The path to the confirmation template
+- ``models`` - A list of models on which the bulk action can act
+- ``action_priority`` (optional) - A number that is used to determine the placement of the button in the list of buttons
+- ``classes`` (optional) - A set of CSS classnames that will be used on the button in the user interface
+
+An example for a confirmation template is as follows:
+
+.. code-block:: django
+
+  <!-- /path/to/confirm_bulk_delete.html -->
+
+  {% extends 'wagtailadmin/bulk_actions/confirmation/base.html' %}
+  {% load i18n wagtailadmin_tags %}
+
+  {% block titletag %}{% blocktrans count counter=items|length %}Delete 1 item{% plural %}Delete {{ counter }} items{% endblocktrans %}{% endblock %}
+
+  {% block header %}
+      {% trans "Delete" as del_str %}
+      {% include "wagtailadmin/shared/header.html" with title=del_str icon="doc-empty-inverse" %}
+  {% endblock header %}
+
+  {% block items_with_access %}
+          {% if items %}
+          <p>{% trans "Are you sure you want to delete these items?" %}</p>
+          <ul>
+              {% for item in items %}
+              <li>
+                  <a href="" target="_blank" rel="noopener noreferrer">{{ item.item.title }}</a>
+              </li>
+              {% endfor %}
+          </ul>
+          {% endif %}
+  {% endblock items_with_access %}
+
+  {% block items_with_no_access %}
+
+  {% blocktrans asvar no_access_msg count counter=items_with_no_access|length %}You don't have permission to delete this item{% plural %}You don't have permission to delete these items{% endblocktrans %}
+  {% include './list_items_with_no_access.html' with items=items_with_no_access no_access_msg=no_access_msg %}
+
+  {% endblock items_with_no_access %}
+
+  {% block form_section %}
+  {% if items %}
+      {% trans 'Yes, delete' as action_button_text %}
+      {% trans "No, don't delete" as no_action_button_text %}
+      {% include 'wagtailadmin/bulk_actions/confirmation/form.html' with action_button_class="serious" %}
+  {% else %}
+      {% include 'wagtailadmin/bulk_actions/confirmation/go_back.html' %}
+  {% endif %}
+  {% endblock form_section %}
+
+
+.. code-block:: django
+
+  <!-- ./list_items_with_no_access.html -->
+  {% extends 'wagtailadmin/bulk_actions/confirmation/list_items_with_no_access.html' %}
+  {% load i18n %}
+
+  {% block per_item %}
+      {% if item.can_edit %}
+      <a href="{% url 'wagtailadmin_pages:edit' item.item.id %}" target="_blank" rel="noopener noreferrer">{{ item.item.title }}</a>
+      {% else %}
+      {{ item.item.title }}
+      {% endif %}
+  {% endblock per_item %}
+
+
+The ``execute_action`` classmethod is the only method that must be overridden for the bulk action to work properly. It
+takes a list of objects as the only required argument, and a bunch of keyword arguments that can be supplied by overriding
+the ``get_execution_context`` method. For example.
+
+  .. code-block:: python
+
+    @classmethod
+    def execute_action(cls, objects, **kwargs):
+      # the kwargs here is the output of the get_execution_context method
+      user = kwargs.get('user', None)
+      num_parent_objects, num_child_objects = 0, 0
+      # you could run the action per object or run them in bulk using django's bulk update and delete methods
+      for obj in objects:
+        num_child_objects += obj.get_children().count()
+        num_parent_objects += 1
+        obj.delete(user=user)
+        num_parent_objects += 1
+      return num_parent_objects, num_child_objects
+
+
+The ``get_execution_context`` method can be overridden to provide context to the ``execute_action``
+
+  .. code-block:: python
+
+    def get_execution_context(self):
+      return {
+        'user': self.request.user
+      }
+
+
+The ``get_context_data`` method can be overridden to pass additional context to the confirmation template.
+
+  .. code-block:: python
+
+    def get_context_data(self, **kwargs):
+      context = super().get_context_data(**kwargs)
+      context['new_key'] = some_value
+      return context
+
+
+The ``check_perm`` method can be overridden to check if an object has some permission or not. objects for which the ``check_perm``
+returns ``False`` will be available in the context under the key ``'items_with_no_access'``.
+
+  .. code-block:: python
+
+    def check_perm(self, obj):
+      return obj.has_perm('some_perm')  # returns True or False
+
+
+The success message shown on the admin can be customised by overriding the ``get_success_message`` method.
+
+  .. code-block:: python
+
+    def get_success_message(self, num_parent_objects, num_child_objects):
+      return _("{} objects, including {} child objects have been updated".format(num_parent_objects, num_child_objects))
+
+
+
+Adding bulk actions to the page explorer
+----------------------------------------
+
+When creating a custom bulk action class for pages, subclass from ``wagtail.admin.views.pages.bulk_actions.page_bulk_action.PageBulkAction``
+instead of ``wagtail.admin.views.bulk_action.BulkAction``
+
+Basic example
+~~~~~~~~~~~~~
+
+  .. code-block:: python
+
+    from wagtail.admin.views.pages.bulk_actions.page_bulk_action import PageBulkAction
+    from wagtail.core import hooks
+
+
+    @hooks.register('register_bulk_action')
+    class CustomPageBulkAction(PageBulkAction):
+        ...
+
+
+
+Adding bulk actions to the Images listing
+-----------------------------------------
+
+When creating a custom bulk action class for images, subclass from ``wagtail.images.views.bulk_actions.image_bulk_action.ImageBulkAction``
+instead of ``wagtail.admin.views.bulk_action.BulkAction``
+
+Basic example
+~~~~~~~~~~~~~
+
+  .. code-block:: python
+
+    from wagtail.images.views.bulk_actions.image_bulk_action import ImageBulkAction
+    from wagtail.core import hooks
+
+
+    @hooks.register('register_bulk_action')
+    class CustomImageBulkAction(ImageBulkAction):
+        ...
+
+
+
+Adding bulk actions to the documents listing
+--------------------------------------------
+
+When creating a custom bulk action class for documents, subclass from ``wagtail.documents.views.bulk_actions.document_bulk_action.DocumentBulkAction``
+instead of ``wagtail.admin.views.bulk_action.BulkAction``
+
+Basic example
+~~~~~~~~~~~~~
+
+  .. code-block:: python
+
+    from wagtail.documents.views.bulk_actions.document_bulk_action import DocumentBulkAction
+    from wagtail.core import hooks
+
+
+    @hooks.register('register_bulk_action')
+    class CustomDocumentBulkAction(DocumentBulkAction):
+        ...
+
+
+
+Adding bulk actions to the user listing
+---------------------------------------
+
+When creating a custom bulk action class for users, subclass from ``wagtail.users.views.bulk_actions.user_bulk_action.UserBulkAction``
+instead of ``wagtail.admin.views.bulk_action.BulkAction``
+
+Basic example
+~~~~~~~~~~~~~
+
+  .. code-block:: python
+
+    from wagtail.users.views.bulk_actions.user_bulk_action import UserBulkAction
+    from wagtail.core import hooks
+
+
+    @hooks.register('register_bulk_action')
+    class CustomUserBulkAction(UserBulkAction):
+        ...
+

+ 1 - 0
docs/extending/index.rst

@@ -19,3 +19,4 @@ This section describes the various mechanisms that can be used to integrate your
     rich_text_internals
     extending_draftail
     extending_hallo
+    custom_bulk_actions

+ 75 - 1
docs/reference/hooks.rst

@@ -433,7 +433,6 @@ More details about the options that are available can be found at :doc:`/extendi
         return queryset
 
 
-
 Editor interface
 ----------------
 
@@ -1390,6 +1389,81 @@ Hooks for working with registered Snippets.
     def remove_snippet_listing_button_item(buttons, snippet, user, context=None):
         buttons.pop()  # Removes the 'delete' button
 
+
+Bulk actions
+------------
+
+Hooks for registering and customising bulk actions. See :ref:`here <custom_bulk_actions>` on how to write custom bulk actions.
+
+
+.. _register_bulk_action:
+
+``register_bulk_action``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  Registers a new bulk action to add to the list of bulk actions in the explorer
+
+  This hook must be registered with a sub-class of ``BulkAction`` . For example:
+
+  .. code-block:: python
+
+    from wagtail.admin.views.bulk_action import BulkAction
+    from wagtail.core import hooks
+
+
+    @hooks.register('register_bulk_action')
+    class CustomBulkAction(BulkAction):
+        display_name = _("Custom Action")
+        action_type = "action"
+        aria_label = _("Do custom action")
+        template_name = "/path/to/template"
+        models = [...]  # list of models the action should execute upon
+
+
+        @classmethod
+        def execute_action(cls, objects, **kwargs):
+            for object in objects:
+                do_something(object)
+            return num_parent_objects, num_child_objects  # return the count of updated objects
+
+
+.. _before_bulk_action:
+
+``before_bulk_action``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  Do something right before a bulk action is executed (before the ``execute_action`` method is called)
+
+  This hook can be used to return an HTTP response. For example:
+
+  .. code-block:: python
+
+    from wagtail.core import hooks
+
+    @hooks.register('before_bulk_action)
+    def hook_func(request, action_type, objects, action_class_instance):
+      ...
+
+
+.. _after_bulk_action:
+
+``after_bulk_action``
+~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+
+  Do something right after a bulk action is executed (after the ``execute_action`` method is called)
+
+  This hook can be used to return an HTTP response. For example:
+
+  .. code-block:: python
+
+    from wagtail.core import hooks
+
+    @hooks.register('after_bulk_action)
+    def hook_func(request, action_type, objects, action_class_instance):
+      ...
+
+
+
 Audit log
 ---------