Even in Wagtail, context information is passed to the template when rendering the page. With the simple usage we've seen so far, you didn't have to be aware of it, but it might be useful to be able to add your own information to the context. Wagtail provides an easy way to do that.
This time, let's add the ListPage
class and keep the standard flow for rendering the page after adding information to the context.
This time as well, add one definition of a new page class (ListPage
class). So, first, let's extend cms/models.py as below.
from django.db import models
from modelcluster.fields import ParentalKey
from wagtail.core.models import Page, Orderable
from wagtail.core.fields import RichTextField
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel, PageChooserPanel
from wagtail.images.edit_handlers import ImageChooserPanel
class TopPage(Page):
...
subpage_types = ['cms.ListPage', 'cms.PlainPage']
class PlainPage(Page):
...
class ListPage(Page):
cover_image = models.ForeignKey(
'wagtailimages.Image',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='+'
)
intro = models.CharField(max_length=255)
main_body = RichTextField(blank=True)
content_panels = Page.content_panels + [
ImageChooserPanel('cover_image'),
FieldPanel('intro'),
FieldPanel('main_body', classname="full"),
InlinePanel('related_pages', label="Related Pages"),
]
parent_page_types = ['cms.TopPage', 'cms.ListPage']
def get_top_page(self):
pages = self.get_ancestors().type(TopPage)
return pages[0]
class NavItems(Orderable):
...
class RelatedPages(Orderable):
base_page = ParentalKey(Page, related_name='related_pages')
page = models.ForeignKey(
Page,
on_delete=models.CASCADE,
related_name='+'
)
panels = [
PageChooserPanel('page'),
]
You can see that the definition of the ListPage
class and the new Orderable
subclass RelatedPages
used there has been added. RelatedPages
is a tool for listing related pages to be displayed on the page of the ListPage
class. It's almost the same as the NavItems
we covered last time, so no detailed explanation is necessary.
The definition of the ListPage
class is almost the same as PlainPage
except that this RelatedPages
is associated. According to the specification of parent_page_types
, this page can be positioned as a child element of TopPage
or ListPage
itself.
In response to the addition of the ListPage
class definition, the child element specification was also added to the TopPage
class.
Next, let's get into the main subject of this time. In other words, let's add unique information to the context passed to the template. This can be easily achieved by overriding the get_context ()
method of the Page
class. Let's look at a concrete example using ListPage
as a subject.
class ListPage(Page):
...
def get_breads(self):
breads = self.get_ancestors().descendant_of(self.get_top_page(), True)
return breads
def get_context(self, request):
context = super().get_context(request)
context['top_page'] = self.get_top_page()
context['breads'] = self.get_breads()
context['page_list'] = [item.page for item in self.related_pages.all()]
return context
Before discussing the get_context ()
method, let's take a quick look at the get_breads ()
method. This is a method that retrieves all the pages from the parent-child relationship back to the top page and returns a list arranged from the top page in reverse order. This will be used for the breadcrumb trail that will be implemented later.
Next, look at the get_context ()
method. After calling the get_context ()
method of the superclass (ie the default Page
class), you can see that it adds a new element to the dictionary context
it returns. Specifically, it is the top page obtained by the get_top_page ()
method, the breadcrumb trail information obtained by the get_breads ()
method, and the list of RelatedPages
associated with this page. By doing this, the information can be easily accessed from the template side.
In fact, this information can be accessed from the template without having to include it in the context, as we saw in the previous implementation of the navigation bar. Therefore, it may be difficult to realize the power of the get_context ()
method. However, this method can also include information in the context that is difficult to access directly from the template, as evidenced by the fact that it takes a request
as an argument (I'll see such an example in the future). ).
In order to unify the templates, let's apply the same extension to the TopPage
class and the PlainPage
class as shown below.
class TopPage(Page):
...
def get_context(self, request):
context = super().get_context(request)
context['top_page'] = self.get_top_page()
return context
class PlainPage(Page):
...
def get_breads(self):
breads = self.get_ancestors().descendant_of(self.get_top_page(), True)
return breads
def get_context(self, request):
context = super().get_context(request)
context['top_page'] = self.get_top_page()
context['breads'] = self.get_breads()
return context
Next, let's make it possible to display the page of the newly added ListPage
class. For that purpose, we prepared the following templates, templates/cms/list_page.html.
{% extends 'cms/plain_page.html' %}
{% load wagtailcore_tags %}
{% block main_body %}
{{ block.super }}
{% for item_page in page_list %}
<hr>
<div class="my-4">
<a href="{% pageurl item_page %}">
<h4>{{ item_page.title }}</h4>
{{ item_page.specific.intro }}
</a>
{% if item_page.last_published_at <= item_page. %}
<p>Posted on {{ item_page.first_published_at|date }}</p>
{% else %}
<p>Last modified on {{ item_page.last_published_at|date }}</p>
{% endif %}
</div>
{% endfor %}
<hr>
{% endblock %}
It can be seen that after inheriting templates/cms/plain_page.html, the rich text is displayed in the main_body block, and then the page information contained in the context page_list
is displayed one by one. Note that first_published_at
and last_published_at
are fields that the default Page
class has, and the values of the first publication date and the last update date are automatically entered respectively.
As in this example, the value of the information added to the context can be accessed directly using that key. Therefore, the description of templates/cms/plain_page.html can be simplified a little. Specifically, let's change all the parts that are page.get_top_page
to top_page
.
Next, let's implement a breadcrumb trail using the information breads
added to the context. Add the display code in templates/cms/plain_page.html so that it will be displayed on all pages. Specifically, a new breadcrumb block was inserted just before the main_body block in the main block as shown below.
...
{% block main %}
...
{% block breadcrumb %}
<nav class="my-2">
<ol class="breadcrumb">
{% for bread in breads %}
<li class="breadcrumb-item">
<a href="{% pageurl bread %}">
{{ bread.title }}
</a>
</li>
{% endfor %}
<li class="breadcrumb-item active">
{{ page.title }}
</li>
</ol>
</nav>
{% endblock %}
{% block main_body %}
....
{% endblock %}
....
{% endblock %}
....
From the context, you can see that the key breads
is used to access the list of pages to be displayed in the breadcrumb trail, the pages are extracted one by one, and the link with the title is displayed.
This time, I introduced a simple way to add unique information to the context passed to the template when rendering the page, and used it to implement a breadcrumb trail.
Next time, let's add the last page class PostPage
and get used to using the convenient field called StraemField
used in it.
-Wagtail Recommendations (1) A story about choosing Wagtail by comparing and examining Django-based CMS -Wagtail Recommendation (2) Let's define, edit, and display the page -Wagtail Recommendation (3) Understand and use the tree structure of the page -Wagtail Recommendation (5) Let's add your own block to StreamField -Wagtail Recommendation (6) Let's add categories and tags
Recommended Posts