123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258 |
- Adding reports
- ==============
- Reports are views with listings of pages matching a specific query. They can also export these listings in spreadsheet format.
- They are found in the `Reports` submenu: by default, the `Locked Pages` report is provided, allowing an overview of locked pages on the site.
- It is possible to create your own custom reports in the Wagtail admin. Two base classes are provided:
- ``wagtail.admin.views.reports.ReportView``, which provides basic listing and spreadsheet export functionality, and
- ``wagtail.admin.views.reports.PageReportView``, which additionally provides a default set of fields suitable for page listings.
- For this example, we'll add a report which shows any pages with unpublished changes.
- .. code-block:: python
- # <project>/views.py
- from wagtail.admin.views.reports import PageReportView
- class UnpublishedChangesReportView(PageReportView):
- pass
- Defining your report
- ~~~~~~~~~~~~~~~~~~~~~
- The most important attributes and methods to customise to define your report are:
- .. method:: get_queryset(self)
- This retrieves the queryset of pages for your report. For our example:
- .. code-block:: python
- # <project>/views.py
- from wagtail.admin.views.reports import PageReportView
- from wagtail.core.models import Page
- class UnpublishedChangesReportView(PageReportView):
- def get_queryset(self):
- return Page.objects.filter(has_unpublished_changes=True)
- .. attribute:: template_name
- (string)
- The template used to render your report. For ``ReportView``, this defaults to ``"wagtailadmin/reports/base_report.html"``,
- which provides an empty report page layout; for ``PageReportView``, this defaults to
- ``"wagtailadmin/reports/base_page_report.html"`` which provides a listing based on the explorer views,
- displaying action buttons, as well as the title, time of the last update, status, and specific type of any pages.
- In this example, we'll change this to a new template in a later section.
- .. attribute:: title
- (string)
- The name of your report, which will be displayed in the header. For our example, we'll set it to
- ``"Pages with unpublished changes"``.
- .. attribute:: header_icon
- (string)
- The name of the icon, using the standard Wagtail icon names. For example, the locked pages view uses ``"locked"``,
- and for our example report, we'll set it to ``'doc-empty-inverse'``.
- Spreadsheet exports
- -------------------
- .. attribute:: list_export
- (list)
- A list of the fields/attributes for each model which are exported as columns in the spreadsheet view. For ``ReportView``, this
- is empty by default, and for ``PageReportView``, it corresponds to the listing fields: the title, time of the last update, status,
- and specific type of any pages. For our example, we might want to know when the page was last published, so we'll set
- ``list_export`` as follows:
- ``list_export = PageReportView.list_export + ['last_published_at']``
- .. attribute:: export_headings
- (dictionary)
- A dictionary of any fields/attributes in ``list_export`` for which you wish to manually specify a heading for the spreadsheet
- column, and their headings. If unspecified, the heading will be taken from the field ``verbose_name`` if applicable, and the
- attribute string otherwise. For our example, ``last_published_at`` will automatically get a heading of ``"Last Published At"``,
- but a simple "Last Published" looks neater. We'll add that by setting ``export_headings``:
- ``export_headings = dict(last_published_at='Last Published', **PageReportView.export_headings)``
- .. attribute:: custom_value_preprocess
- (dictionary)
- A dictionary of ``(value_class_1, value_class_2, ...)`` tuples mapping to ``{export_format: preprocessing_function}`` dictionaries,
- allowing custom preprocessing functions to be applied when exporting field values of specific classes (or their subclasses). If
- unspecified (and ``ReportView.custom_field_preprocess`` also does not specify a function), ``force_str`` will be used. To prevent
- preprocessing, set the preprocessing_function to ``None``.
- .. attribute:: custom_field_preprocess
- (dictionary)
- A dictionary of ``field_name`` strings mapping to ``{export_format: preprocessing_function}`` dictionaries,
- allowing custom preprocessing functions to be applied when exporting field values of specific classes (or their subclasses). This
- will take priority over functions specified in ``ReportView.custom_value_preprocess``. If unspecified (and
- ``ReportView.custom_value_preprocess`` also does not specify a function), ``force_str`` will be used. To prevent
- preprocessing, set the preprocessing_function to ``None``.
- Customising templates
- ---------------------
- For this example "pages with unpublished changes" report, we'll add an extra column to the listing template, showing the last
- publication date for each page. To do this, we'll extend two templates: ``wagtailadmin/reports/base_page_report.html``, and
- ``wagtailadmin/reports/listing/_list_page_report.html``.
- .. code-block:: html+django
- {# <project>/templates/reports/unpublished_changes_report.html #}
- {% extends 'wagtailadmin/reports/base_page_report.html' %}
- {% block listing %}
- {% include 'reports/include/_list_unpublished_changes.html' %}
- {% endblock %}
- {% block no_results %}
- <p>No pages with unpublished changes.</p>
- {% endblock %}
- .. code-block:: html+django
- {# <project>/templates/reports/include/_list_unpublished_changes.html #}
- {% extends 'wagtailadmin/reports/listing/_list_page_report.html' %}
- {% block extra_columns %}
- <th>Last Published</th>
- {% endblock %}
- {% block extra_page_data %}
- <td valign="top">
- {{ page.last_published_at }}
- </td>
- {% endblock %}
- Finally, we'll set ``UnpublishedChangesReportView.template_name`` to this new template: ``'reports/unpublished_changes_report.html'``.
- Adding a menu item and admin URL
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- To add a menu item for your new report to the `Reports` submenu, you will need to use the ``register_reports_menu_item`` hook (see: :ref:`register_reports_menu_item`). To add an admin
- url for the report, you will need to use the ``register_admin_urls`` hook (see :ref:`register_admin_urls`). This can be done as follows:
- .. code-block:: python
- # <project>/wagtail_hooks.py
- from django.urls import path, reverse
- from wagtail.admin.menu import AdminOnlyMenuItem
- from wagtail.core import hooks
- from .views import UnpublishedChangesReportView
- @hooks.register('register_reports_menu_item')
- def register_unpublished_changes_report_menu_item():
- return AdminOnlyMenuItem("Pages with unpublished changes", reverse('unpublished_changes_report'), classnames='icon icon-' + UnpublishedChangesReportView.header_icon, order=700)
- @hooks.register('register_admin_urls')
- def register_unpublished_changes_report_url():
- return [
- path('reports/unpublished-changes/', UnpublishedChangesReportView.as_view(), name='unpublished_changes_report'),
- ]
- Here, we use the ``AdminOnlyMenuItem`` class to ensure our report icon is only shown to superusers. To make the report visible to all users,
- you could replace this with ``MenuItem``.
- The full code
- ~~~~~~~~~~~~~
- .. code-block:: python
- # <project>/views.py
- from wagtail.admin.views.reports import PageReportView
- from wagtail.core.models import Page
- class UnpublishedChangesReportView(PageReportView):
- header_icon = 'doc-empty-inverse'
- template_name = 'reports/unpublished_changes_report.html'
- title = "Pages with unpublished changes"
- list_export = PageReportView.list_export + ['last_published_at']
- export_headings = dict(last_published_at='Last Published', **PageReportView.export_headings)
- def get_queryset(self):
- return Page.objects.filter(has_unpublished_changes=True)
- .. code-block:: python
- # <project>/wagtail_hooks.py
- from django.urls import path, reverse
- from wagtail.admin.menu import AdminOnlyMenuItem
- from wagtail.core import hooks
- from .views import UnpublishedChangesReportView
- @hooks.register('register_reports_menu_item')
- def register_unpublished_changes_report_menu_item():
- return AdminOnlyMenuItem("Pages with unpublished changes", reverse('unpublished_changes_report'), classnames='icon icon-' + UnpublishedChangesReportView.header_icon, order=700)
- @hooks.register('register_admin_urls')
- def register_unpublished_changes_report_url():
- return [
- path('reports/unpublished-changes/', UnpublishedChangesReportView.as_view(), name='unpublished_changes_report'),
- ]
- .. code-block:: html+django
- {# <project>/templates/reports/unpublished_changes_report.html #}
- {% extends 'wagtailadmin/reports/base_page_report.html' %}
- {% block listing %}
- {% include 'reports/include/_list_unpublished_changes.html' %}
- {% endblock %}
- {% block no_results %}
- <p>No pages with unpublished changes.</p>
- {% endblock %}
- .. code-block:: html+django
- {# <project>/templates/reports/include/_list_unpublished_changes.html #}
- {% extends 'wagtailadmin/reports/listing/_list_page_report.html' %}
- {% block extra_columns %}
- <th>Last Published</th>
- {% endblock %}
- {% block extra_page_data %}
- <td valign="top">
- {{ page.last_published_at }}
- </td>
- {% endblock %}
|