routablepage.rst 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. .. _routable_page_mixin:
  2. =====================
  3. ``RoutablePageMixin``
  4. =====================
  5. .. module:: wagtail.contrib.routable_page
  6. The ``RoutablePageMixin`` mixin provides a convenient way for a page to respond on multiple sub-URLs with different views. For example, a blog section on a site might provide several different types of index page at URLs like ``/blog/2013/06/``, ``/blog/authors/bob/``, ``/blog/tagged/python/``, all served by the same page instance.
  7. A ``Page`` using ``RoutablePageMixin`` exists within the page tree like any other page, but URL paths underneath it are checked against a list of patterns. If none of the patterns match, control is passed to subpages as usual (or failing that, a 404 error is thrown).
  8. By default a route for ``r'^$'`` exists, which serves the content exactly like a normal ``Page`` would. It can be overridden by using ``@route(r'^$')`` on any other method of the inheriting class.
  9. Installation
  10. ============
  11. Add ``"wagtail.contrib.routable_page"`` to your INSTALLED_APPS:
  12. .. code-block:: python
  13. INSTALLED_APPS = [
  14. ...
  15. "wagtail.contrib.routable_page",
  16. ]
  17. The basics
  18. ==========
  19. To use ``RoutablePageMixin``, you need to make your class inherit from both :class:`wagtail.contrib.routable_page.models.RoutablePageMixin` and :class:`wagtail.core.models.Page`, then define some view methods and decorate them with ``wagtail.contrib.routable_page.models.route``. These view methods behave like ordinary Django view functions, and must return an ``HttpResponse`` object; typically this is done through a call to ``django.shortcuts.render``.
  20. Here's an example of an ``EventIndexPage`` with three views, assuming that an ``EventPage`` model with an ``event_date`` field has been defined elsewhere:
  21. .. code-block:: python
  22. import datetime
  23. from django.http import JsonResponse
  24. from wagtail.core.fields import RichTextField
  25. from wagtail.core.models import Page
  26. from wagtail.contrib.routable_page.models import RoutablePageMixin, route
  27. class EventIndexPage(RoutablePageMixin, Page):
  28. # Routable pages can have fields like any other - here we would
  29. # render the intro text on a template with {{ page.intro|richtext }}
  30. intro = RichTextField()
  31. @route(r'^$') # will override the default Page serving mechanism
  32. def current_events(self, request):
  33. """
  34. View function for the current events page
  35. """
  36. events = EventPage.objects.live().filter(event_date__gte=datetime.date.today())
  37. # NOTE: We can use the RoutablePageMixin.render() method to render
  38. # the page as normal, but with some of the context values overridden
  39. return self.render(request, context_overrides={
  40. 'title': "Current events",
  41. 'events': events,
  42. })
  43. @route(r'^past/$')
  44. def past_events(self, request):
  45. """
  46. View function for the past events page
  47. """
  48. events = EventPage.objects.live().filter(event_date__lt=datetime.date.today())
  49. # NOTE: We are overriding the template here, as well as few context values
  50. return self.render(
  51. request,
  52. context_overrides={
  53. 'title': "Past events",
  54. 'events': events,
  55. },
  56. template="events/event_index_historical.html",
  57. )
  58. # Multiple routes!
  59. @route(r'^year/(\d+)/$')
  60. @route(r'^year/current/$')
  61. def events_for_year(self, request, year=None):
  62. """
  63. View function for the events for year page
  64. """
  65. if year is None:
  66. year = datetime.date.today().year
  67. events = EventPage.objects.live().filter(event_date__year=year)
  68. return self.render(request, context_overrides={
  69. 'title': "Events for %d" % year,
  70. 'events': events,
  71. })
  72. @route(r'^year/(\d+)/count/$')
  73. def count_for_year(self, request, year=None):
  74. """
  75. View function that returns a simple JSON response that
  76. includes the number of events scheduled for a specific year
  77. """
  78. events = EventPage.objects.live().filter(event_date__year=year)
  79. # NOTE: The usual template/context rendering process is irrelevant
  80. # here, so we'll just return a HttpResponse directly
  81. return JsonResponse({'count': events.count()})
  82. Rendering other pages
  83. =====================
  84. Another way of returning an ``HttpResponse`` is to call the ``serve`` method of another page. (Calling a page's own ``serve`` method within a view method is not valid, as the view method is already being called within ``serve``, and this would create a circular definition).
  85. For example, ``EventIndexPage`` could be extended with a ``next/`` route that displays the page for the next event:
  86. .. code-block:: python
  87. @route(r'^next/$')
  88. def next_event(self, request):
  89. """
  90. Display the page for the next event
  91. """
  92. future_events = EventPage.objects.live().filter(event_date__gt=datetime.date.today())
  93. next_event = future_events.order_by('event_date').first()
  94. return next_event.serve(request)
  95. Reversing URLs
  96. ==============
  97. :class:`~models.RoutablePageMixin` adds a :meth:`~models.RoutablePageMixin.reverse_subpage` method to your page model which you can use for reversing URLs. For example:
  98. .. code-block:: python
  99. # The URL name defaults to the view method name.
  100. >>> event_page.reverse_subpage('events_for_year', args=(2015, ))
  101. 'year/2015/'
  102. This method only returns the part of the URL within the page. To get the full URL, you must append it to the values of either the :attr:`~wagtail.core.models.Page.url` or the :attr:`~wagtail.core.models.Page.full_url` attribute on your page:
  103. .. code-block:: python
  104. >>> event_page.url + event_page.reverse_subpage('events_for_year', args=(2015, ))
  105. '/events/year/2015/'
  106. >>> event_page.full_url + event_page.reverse_subpage('events_for_year', args=(2015, ))
  107. 'http://example.com/events/year/2015/'
  108. Changing route names
  109. --------------------
  110. The route name defaults to the name of the view. You can override this name with the ``name`` keyword argument on ``@route``:
  111. .. code-block:: python
  112. from wagtail.core.models import Page
  113. from wagtail.contrib.routable_page.models import RoutablePageMixin, route
  114. class EventPage(RoutablePageMixin, Page):
  115. ...
  116. @route(r'^year/(\d+)/$', name='year')
  117. def events_for_year(self, request, year):
  118. """
  119. View function for the events for year page
  120. """
  121. ...
  122. .. code-block:: python
  123. >>> event_page.url + event_page.reverse_subpage('year', args=(2015, ))
  124. '/events/year/2015/'
  125. The ``RoutablePageMixin`` class
  126. ===============================
  127. .. automodule:: wagtail.contrib.routable_page.models
  128. .. autoclass:: RoutablePageMixin
  129. .. automethod:: render
  130. .. automethod:: get_subpage_urls
  131. .. automethod:: resolve_subpage
  132. Example:
  133. .. code-block:: python
  134. view, args, kwargs = page.resolve_subpage('/past/')
  135. response = view(request, *args, **kwargs)
  136. .. automethod:: reverse_subpage
  137. Example:
  138. .. code-block:: python
  139. url = page.url + page.reverse_subpage('events_for_year', kwargs={'year': '2014'})
  140. .. _routablepageurl_template_tag:
  141. The ``routablepageurl`` template tag
  142. ====================================
  143. .. currentmodule:: wagtail.contrib.routable_page.templatetags.wagtailroutablepage_tags
  144. .. autofunction:: routablepageurl
  145. Example:
  146. .. code-block:: html+django
  147. {% load wagtailroutablepage_tags %}
  148. {% routablepageurl page "feed" %}
  149. {% routablepageurl page "archive" 2014 08 14 %}
  150. {% routablepageurl page "food" foo="bar" baz="quux" %}