admin_views.rst 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. Creating admin views
  2. ====================
  3. The most common use for adding custom views to the Wagtail admin is to provide an interface for managing a Django model. The :doc:`/reference/contrib/modeladmin/index` app makes this simple, providing ready-made views for listing, creating and editing objects with minimal configuration.
  4. For other kinds of admin view that don't fit this pattern, you can write your own Django views and register them as part of the Wagtail admin through :ref:`hooks <admin_hooks>`. In this example, we'll implement a view that displays a calendar for the current year, using `the calendar module <https://docs.python.org/3/library/calendar.html>`_ from Python's standard library.
  5. Defining a view
  6. ---------------
  7. Within a Wagtail project, create a new ``wagtailcalendar`` app with ``./manage.py startapp wagtailcalendar`` and add it to your project's ``INSTALLED_APPS``. (In this case we're using the name 'wagtailcalendar' to avoid clashing with the standard library's ``calendar`` module - in general there is no need to use a 'wagtail' prefix.)
  8. Edit ``views.py`` as follows - note that this is a plain Django view with no Wagtail-specific code.
  9. .. code-block:: python
  10. import calendar
  11. from django.http import HttpResponse
  12. from django.utils import timezone
  13. def index(request):
  14. current_year = timezone.now().year
  15. calendar_html = calendar.HTMLCalendar().formatyear(current_year)
  16. return HttpResponse(calendar_html)
  17. Registering a URL route
  18. -----------------------
  19. At this point, the standard practice for a Django project would be to add a URL route for this view to your project's top-level URL config module. However, in this case we want the view to only be available to logged-in users, and to appear within the ``/admin/`` URL namespace which is managed by Wagtail. This is done through the :ref:`register_admin_urls` hook.
  20. On startup, Wagtail looks for a ``wagtail_hooks`` submodule within each installed app. In this submodule, you can define functions to be run at various points in Wagtail's operation, such as building the URL config for the admin, and constructing the main menu.
  21. Create a ``wagtail_hooks.py`` file within the ``wagtailcalendar`` app containing the following:
  22. .. code-block:: python
  23. from django.urls import path
  24. from wagtail.core import hooks
  25. from .views import index
  26. @hooks.register('register_admin_urls')
  27. def register_calendar_url():
  28. return [
  29. path('calendar/', index, name='calendar'),
  30. ]
  31. The calendar will now be visible at the URL ``/admin/calendar/``.
  32. .. figure:: ../_static/images/adminviews_calendar.png
  33. :alt: A calendar, presented in unstyled HTML
  34. Adding a template
  35. -----------------
  36. Currently this view is outputting a plain HTML fragment. Let's insert this into the usual Wagtail admin page furniture, by creating a template that extends Wagtail's base template ``"wagtailadmin/base.html"``.
  37. .. note::
  38. The base template and HTML structure are not considered a stable part of Wagtail's API, and may change in future releases.
  39. Update ``views.py`` as follows:
  40. .. code-block:: python
  41. import calendar
  42. from django.shortcuts import render
  43. from django.utils import timezone
  44. def index(request):
  45. current_year = timezone.now().year
  46. calendar_html = calendar.HTMLCalendar().formatyear(current_year)
  47. return render(request, 'wagtailcalendar/index.html', {
  48. 'current_year': current_year,
  49. 'calendar_html': calendar_html,
  50. })
  51. Now create a ``templates/wagtailcalendar/`` folder within the ``wagtailcalendar`` app, containing ``index.html`` as follows:
  52. .. code-block:: html+django
  53. {% extends "wagtailadmin/base.html" %}
  54. {% block titletag %}{{ current_year }} calendar{% endblock %}
  55. {% block extra_css %}
  56. {{ block.super }}
  57. <style>
  58. table.month {
  59. margin: 20px;
  60. }
  61. table.month td, table.month th {
  62. padding: 5px;
  63. }
  64. </style>
  65. {% endblock %}
  66. {% block content %}
  67. {% include "wagtailadmin/shared/header.html" with title="Calendar" icon="date" %}
  68. <div class="nice-padding">
  69. {{ calendar_html|safe }}
  70. </div>
  71. {% endblock %}
  72. Here we are overriding three of the blocks defined in the base template: ``titletag`` (which sets the content of the HTML ``<title>`` tag), ``extra_css`` (which allows us to provide additional CSS styles specific to this page), and ``content`` (for the main content area of the page). We're also including the standard header bar component, and setting a title and icon. For a list of the recognised icon identifiers, see the :ref:`styleguide`.
  73. Revisiting ``/admin/calendar/`` will now show the calendar within the Wagtail admin page furniture.
  74. .. figure:: ../_static/images/adminviews_calendar_template.png
  75. :alt: A calendar, shown within the Wagtail admin interface
  76. Adding a menu item
  77. ------------------
  78. Our calendar view is now complete, but there's no way to reach it from the rest of the admin backend. To add an item to the sidebar menu, we'll use another hook, :ref:`register_admin_menu_item`. Update ``wagtail_hooks.py`` as follows:
  79. .. code-block:: python
  80. from django.urls import path, reverse
  81. from wagtail.admin.menu import MenuItem
  82. from wagtail.core import hooks
  83. from .views import index
  84. @hooks.register('register_admin_urls')
  85. def register_calendar_url():
  86. return [
  87. path('calendar/', index, name='calendar'),
  88. ]
  89. @hooks.register('register_admin_menu_item')
  90. def register_calendar_menu_item():
  91. return MenuItem('Calendar', reverse('calendar'), icon_name='date')
  92. A 'Calendar' item will now appear in the menu.
  93. .. figure:: ../_static/images/adminviews_menu.png
  94. :alt: Wagtail admin sidebar menu, showing a "Calendar" menu item with a date icon