Wagtail Tutorial Series:
To learn more about Wagtail CMS, please check Build Blog With Wagtail CMS (4.0.0)
- Create Wagtail Project
- Modern Frontend Techs for Wagtail
- Dockerizing Wagtail App
- Add Blog Models to Wagtail
- How to write Wagtail page template
- Create Stylish Wagtail Pages with Tailwind CSS
- How to use StreamField in Wagtail
- Wagtail Routable Page
- Add Pagination Component to Wagtail
- Customize Wagtail Page URL
- Add Full Text Search to Wagtail
- Add Markdown Support to Wagtail
- Add LaTeX Support & Code Highlight In Wagtail
- How to Build Form Page in Wagtail
- How to Create and Manage Menus in Wagtail
- Wagtail SEO Guide
- Online Demo http://wagtail-blog.accordbox.com/
- Source code: https://github.com/AccordBox/wagtail-tailwind-blog
Wagtail Tips:
- Wagtail Tip #1: How to replace ParentalManyToManyField with InlinePanel
- Wagtail Tip #2: How to Export & Restore Wagtail Site
Write style in Wagtail:
- How to use SCSS/SASS in your Django project (Python Way)
- How to use SCSS/SASS in your Django project (NPM Way)
Other Wagtail Topics:
Objectives
By the end of this chapter, you should be able to:
- Learn how to build
pagination
with DjangoPaginator
- Handle the querystring with custom Django template tag
Pagination
Let's add pagination to our BlotPage
Update BlogPage.get_context
in wagtail_app/blog/models.py
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
class BlogPage(RoutablePageMixin, Page):
def get_context(self, request, *args, **kwargs):
context = super(BlogPage, self).get_context(request, *args, **kwargs)
context['blog_page'] = self
context['posts'] = self.get_paginated_posts(request, self.posts)
return context
def get_posts(self):
return PostPage.objects.descendant_of(self).live()
def get_paginated_posts(self, request, qs):
# https://docs.djangoproject.com/en/4.0/topics/pagination/#using-paginator-in-a-view-function
paginator = Paginator(qs, 2)
page = request.GET.get("page")
try:
posts = paginator.page(page)
except PageNotAnInteger:
posts = paginator.page(1)
except EmptyPage:
posts = paginator.object_list.none()
return posts
Notes:
- In
get_paginated_posts
, we use DjangoPaginator
to create paginator instance from theself.posts
, the number2
here is the number of item per page. - The page number is from the URl querystring
?page=
Next, let's add pagination component to the wagtail_app/templates/blog/blog_page.html
{# Pagination #}
{# https://docs.djangoproject.com/en/4.0/topics/pagination/#paginating-a-listview #}
<nav aria-label="Page navigation">
<ul class="flex pl-0 rounded list-none flex-wrap">
{% if posts.has_previous %}
<li>
<a href="?page={{ posts.previous_page_number }}"
class="text-blue-500 dark:text-white inline-block py-2 px-4 bg-white border border-gray-300 border-r-0 rounded-l-lg hover:bg-blue-500 hover:text-white">
Previous
</a>
</li>
{% else %}
<li>
<a href="#" class="pointer-events-none text-gray-300 inline-block py-2 px-4 bg-white border border-gray-300 border-r-0 rounded-l-lg hover:bg-blue-500 hover:text-white">
Previous
</a>
</li>
{% endif %}
{% if posts.has_next %}
<li>
<a href="?page={{ posts.next_page_number }}"
class="text-blue-500 dark:text-white inline-block py-2 px-4 bg-white border border-gray-300 rounded-r-lg hover:bg-blue-500 hover:text-white">
Next
</a>
</li>
{% else %}
<li>
<a href="#" class="pointer-events-none text-gray-300 inline-block py-2 px-4 bg-white border border-gray-300 rounded-r-lg hover:bg-blue-500 hover:text-white">
Next
</a>
</li>
{% endif %}
</ul>
</nav>
Notes:
- We use
?page={{ posts.previous_page_number }}
to append thepage
querystring to the url to make pagination work. - As for the
number of item per page
, you can get it from the page field, or even Django global settings.
URL Which Already has Querystring
Let's take a look at this URL http://www.example.com/?q=wagtail
If we use code above to generate the next page url
, it would be http://127.0.0.1:8000/?q=wagtail?page=2
, the q=wagtail
is dropped by the browser, and we would visit http://127.0.0.1:8000/?page=2
This is not correct, and we should use a better way to handle the querystring in the URL.
Update wagtail_app/blog/templatetags/blogapp_tags.py
from urllib.parse import urlparse, urlunparse
from django.http import QueryDict
@register.simple_tag
def url_replace(request, **kwargs):
"""
This tag can help us replace or add querystring
TO replace the page field in URL
{% url_replace request page=page_num %}
"""
(scheme, netloc, path, params, query, fragment) = urlparse(request.get_full_path())
query_dict = QueryDict(query, mutable=True)
for key, value in kwargs.items():
query_dict[key] = value
query = query_dict.urlencode()
return urlunparse((scheme, netloc, path, params, query, fragment))
Notes:
- Here we added a django template tag to help us solve the problem.
- It would get the
query_dict
from the current request url, and then use thekwargs
to generate the new url.
Update pagination in wagtail_app/templates/blog/blog_page.html
{% load wagtailcore_tags wagtailimages_tags blogapp_tags %}
...
<nav aria-label="Page navigation">
<ul class="flex pl-0 rounded list-none flex-wrap">
{% if posts.has_previous %}
<li>
<a href="{% url_replace request page=posts.previous_page_number %}"
class="text-blue-500 dark:text-white inline-block py-2 px-4 bg-white border border-gray-300 border-r-0 rounded-l-lg hover:bg-blue-500 hover:text-white">
Previous
</a>
</li>
{% else %}
<li>
<a href="#" class="pointer-events-none text-gray-300 inline-block py-2 px-4 bg-white border border-gray-300 border-r-0 rounded-l-lg hover:bg-blue-500 hover:text-white">
Previous
</a>
</li>
{% endif %}
{% if posts.has_next %}
<li>
<a href="{% url_replace request page=posts.next_page_number %}"
class="text-blue-500 dark:text-white inline-block py-2 px-4 bg-white border border-gray-300 rounded-r-lg hover:bg-blue-500 hover:text-white">
Next
</a>
</li>
{% else %}
<li>
<a href="#" class="pointer-events-none text-gray-300 inline-block py-2 px-4 bg-white border border-gray-300 rounded-r-lg hover:bg-blue-500 hover:text-white">
Next
</a>
</li>
{% endif %}
</ul>
</nav>
Notes:
- Import
blogapp_tags
at the top of the template. - We replaced
?page={{ posts.previous_page_number }}
with{% url_replace request page=posts.previous_page_number %}
- The
url_replace
would help us keep existing querystring in the url when addingpage
querystring.
Now if we visit http://127.0.0.1:8000/?q=wagtail
the generated next page url will be http://127.0.0.1:8000/?q=wagtail&page=2
Wagtail Tutorial Series:
To learn more about Wagtail CMS, please check Build Blog With Wagtail CMS (4.0.0)
- Create Wagtail Project
- Modern Frontend Techs for Wagtail
- Dockerizing Wagtail App
- Add Blog Models to Wagtail
- How to write Wagtail page template
- Create Stylish Wagtail Pages with Tailwind CSS
- How to use StreamField in Wagtail
- Wagtail Routable Page
- Add Pagination Component to Wagtail
- Customize Wagtail Page URL
- Add Full Text Search to Wagtail
- Add Markdown Support to Wagtail
- Add LaTeX Support & Code Highlight In Wagtail
- How to Build Form Page in Wagtail
- How to Create and Manage Menus in Wagtail
- Wagtail SEO Guide
- Online Demo http://wagtail-blog.accordbox.com/
- Source code: https://github.com/AccordBox/wagtail-tailwind-blog
Wagtail Tips:
- Wagtail Tip #1: How to replace ParentalManyToManyField with InlinePanel
- Wagtail Tip #2: How to Export & Restore Wagtail Site
Write style in Wagtail:
- How to use SCSS/SASS in your Django project (Python Way)
- How to use SCSS/SASS in your Django project (NPM Way)
Other Wagtail Topics: