custom_bulk_actions.rst 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243
  1. .. _custom_bulk_actions:
  2. Adding custom bulk actions
  3. ==========================================
  4. This document describes how to add custom bulk actions to different listings.
  5. Registering a custom bulk action
  6. --------------------------------
  7. .. code-block:: python
  8. from wagtail.admin.views.bulk_action import BulkAction
  9. from wagtail.core import hooks
  10. @hooks.register('register_bulk_action')
  11. class CustomDeleteBulkAction(BulkAction):
  12. display_name = _("Delete")
  13. aria_label = _("Delete selected objects")
  14. action_type = "delete"
  15. template_name = "/path/to/confirm_bulk_delete.html"
  16. models = [...]
  17. @classmethod
  18. def execute_action(cls, objects, **kwargs):
  19. for obj in objects:
  20. do_something(obj)
  21. return num_parent_objects, num_child_objects # return the count of updated objects
  22. The attributes are as follows:
  23. - ``display_name`` - The label that will be displayed on the button in the user interface
  24. - ``aria_label`` - The ``aria-label`` attribute that will be applied to the button in the user interface
  25. - ``action_type`` - A unique identifier for the action. Will be required in the url for bulk actions
  26. - ``template_name`` - The path to the confirmation template
  27. - ``models`` - A list of models on which the bulk action can act
  28. - ``action_priority`` (optional) - A number that is used to determine the placement of the button in the list of buttons
  29. - ``classes`` (optional) - A set of CSS classnames that will be used on the button in the user interface
  30. An example for a confirmation template is as follows:
  31. .. code-block:: django
  32. <!-- /path/to/confirm_bulk_delete.html -->
  33. {% extends 'wagtailadmin/bulk_actions/confirmation/base.html' %}
  34. {% load i18n wagtailadmin_tags %}
  35. {% block titletag %}{% blocktrans count counter=items|length %}Delete 1 item{% plural %}Delete {{ counter }} items{% endblocktrans %}{% endblock %}
  36. {% block header %}
  37. {% trans "Delete" as del_str %}
  38. {% include "wagtailadmin/shared/header.html" with title=del_str icon="doc-empty-inverse" %}
  39. {% endblock header %}
  40. {% block items_with_access %}
  41. {% if items %}
  42. <p>{% trans "Are you sure you want to delete these items?" %}</p>
  43. <ul>
  44. {% for item in items %}
  45. <li>
  46. <a href="" target="_blank" rel="noopener noreferrer">{{ item.item.title }}</a>
  47. </li>
  48. {% endfor %}
  49. </ul>
  50. {% endif %}
  51. {% endblock items_with_access %}
  52. {% block items_with_no_access %}
  53. {% 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 %}
  54. {% include './list_items_with_no_access.html' with items=items_with_no_access no_access_msg=no_access_msg %}
  55. {% endblock items_with_no_access %}
  56. {% block form_section %}
  57. {% if items %}
  58. {% trans 'Yes, delete' as action_button_text %}
  59. {% trans "No, don't delete" as no_action_button_text %}
  60. {% include 'wagtailadmin/bulk_actions/confirmation/form.html' with action_button_class="serious" %}
  61. {% else %}
  62. {% include 'wagtailadmin/bulk_actions/confirmation/go_back.html' %}
  63. {% endif %}
  64. {% endblock form_section %}
  65. .. code-block:: django
  66. <!-- ./list_items_with_no_access.html -->
  67. {% extends 'wagtailadmin/bulk_actions/confirmation/list_items_with_no_access.html' %}
  68. {% load i18n %}
  69. {% block per_item %}
  70. {% if item.can_edit %}
  71. <a href="{% url 'wagtailadmin_pages:edit' item.item.id %}" target="_blank" rel="noopener noreferrer">{{ item.item.title }}</a>
  72. {% else %}
  73. {{ item.item.title }}
  74. {% endif %}
  75. {% endblock per_item %}
  76. The ``execute_action`` classmethod is the only method that must be overridden for the bulk action to work properly. It
  77. takes a list of objects as the only required argument, and a bunch of keyword arguments that can be supplied by overriding
  78. the ``get_execution_context`` method. For example.
  79. .. code-block:: python
  80. @classmethod
  81. def execute_action(cls, objects, **kwargs):
  82. # the kwargs here is the output of the get_execution_context method
  83. user = kwargs.get('user', None)
  84. num_parent_objects, num_child_objects = 0, 0
  85. # you could run the action per object or run them in bulk using django's bulk update and delete methods
  86. for obj in objects:
  87. num_child_objects += obj.get_children().count()
  88. num_parent_objects += 1
  89. obj.delete(user=user)
  90. num_parent_objects += 1
  91. return num_parent_objects, num_child_objects
  92. The ``get_execution_context`` method can be overridden to provide context to the ``execute_action``
  93. .. code-block:: python
  94. def get_execution_context(self):
  95. return {
  96. 'user': self.request.user
  97. }
  98. The ``get_context_data`` method can be overridden to pass additional context to the confirmation template.
  99. .. code-block:: python
  100. def get_context_data(self, **kwargs):
  101. context = super().get_context_data(**kwargs)
  102. context['new_key'] = some_value
  103. return context
  104. The ``check_perm`` method can be overridden to check if an object has some permission or not. objects for which the ``check_perm``
  105. returns ``False`` will be available in the context under the key ``'items_with_no_access'``.
  106. .. code-block:: python
  107. def check_perm(self, obj):
  108. return obj.has_perm('some_perm') # returns True or False
  109. The success message shown on the admin can be customised by overriding the ``get_success_message`` method.
  110. .. code-block:: python
  111. def get_success_message(self, num_parent_objects, num_child_objects):
  112. return _("{} objects, including {} child objects have been updated".format(num_parent_objects, num_child_objects))
  113. Adding bulk actions to the page explorer
  114. ----------------------------------------
  115. When creating a custom bulk action class for pages, subclass from ``wagtail.admin.views.pages.bulk_actions.page_bulk_action.PageBulkAction``
  116. instead of ``wagtail.admin.views.bulk_action.BulkAction``
  117. Basic example
  118. ~~~~~~~~~~~~~
  119. .. code-block:: python
  120. from wagtail.admin.views.pages.bulk_actions.page_bulk_action import PageBulkAction
  121. from wagtail.core import hooks
  122. @hooks.register('register_bulk_action')
  123. class CustomPageBulkAction(PageBulkAction):
  124. ...
  125. Adding bulk actions to the Images listing
  126. -----------------------------------------
  127. When creating a custom bulk action class for images, subclass from ``wagtail.images.views.bulk_actions.image_bulk_action.ImageBulkAction``
  128. instead of ``wagtail.admin.views.bulk_action.BulkAction``
  129. Basic example
  130. ~~~~~~~~~~~~~
  131. .. code-block:: python
  132. from wagtail.images.views.bulk_actions.image_bulk_action import ImageBulkAction
  133. from wagtail.core import hooks
  134. @hooks.register('register_bulk_action')
  135. class CustomImageBulkAction(ImageBulkAction):
  136. ...
  137. Adding bulk actions to the documents listing
  138. --------------------------------------------
  139. When creating a custom bulk action class for documents, subclass from ``wagtail.documents.views.bulk_actions.document_bulk_action.DocumentBulkAction``
  140. instead of ``wagtail.admin.views.bulk_action.BulkAction``
  141. Basic example
  142. ~~~~~~~~~~~~~
  143. .. code-block:: python
  144. from wagtail.documents.views.bulk_actions.document_bulk_action import DocumentBulkAction
  145. from wagtail.core import hooks
  146. @hooks.register('register_bulk_action')
  147. class CustomDocumentBulkAction(DocumentBulkAction):
  148. ...
  149. Adding bulk actions to the user listing
  150. ---------------------------------------
  151. When creating a custom bulk action class for users, subclass from ``wagtail.users.views.bulk_actions.user_bulk_action.UserBulkAction``
  152. instead of ``wagtail.admin.views.bulk_action.BulkAction``
  153. Basic example
  154. ~~~~~~~~~~~~~
  155. .. code-block:: python
  156. from wagtail.users.views.bulk_actions.user_bulk_action import UserBulkAction
  157. from wagtail.core import hooks
  158. @hooks.register('register_bulk_action')
  159. class CustomUserBulkAction(UserBulkAction):
  160. ...