Learn Wagtail CMS Course

How to Paginate Your Wagtail Pages

Pagination is the ability to click through "pages". You most commonly see this on a Blog Listing Page, where you have "page 1 of 4" for example.

In this lesson we're going to Django Paginator right out of the box to add pagination to our Wagtail Blog Listing Page. No 3rd party packages, no craziness, minimal maintenance. Below is the the code we used in this video, but if you're looking to learn more about the code (like the exceptions that were used), the video covers all of that.

"""blog/models.py"""
from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from wagtail.core.models import Page


class BlogListingPage(Page):
    """Listing page lists all the Blog Detail Pages."""

    template = "blog/blog_listing_page.html"

    def get_context(self, request, *args, **kwargs):
        """Adding custom stuff to our context."""
        context = super().get_context(request, *args, **kwargs)
        # Get all posts
        all_posts = BlogDetailPage.objects.live().public().order_by('-first_published_at')
        # Paginate all posts by 2 per page
        paginator = Paginator(all_posts, 2)
        # Try to get the ?page=x value
        page = request.GET.get("page")
        try:
            # If the page exists and the ?page=x is an int
            posts = paginator.page(page)
        except PageNotAnInteger:
            # If the ?page=x is not an int; show the first page
            posts = paginator.page(1)
        except EmptyPage:
            # If the ?page=x is out of range (too high most likely)
            # Then return the last page
            posts = paginator.page(paginator.num_pages)

        # "posts" will have child pages; you'll need to use .specific in the template
        # in order to access child properties, such as youtube_video_id and subtitle
        context["posts"] = posts
        return context
{% extends "base.html" %}
{# templates/blog/blog_listing_page.html #}


{% block content %}
  {% comment %}
    {% for post in posts %}
      {{ post.url }}
    {% endfor %}
  {% endcomment %}

  {# Only show pagination if there is more than one page to click through #}
  {% if posts.paginator.num_pages > 1 %}
    <div class="container">
      <div class="row">
        <div class="col-lg-12">
          <div class="pagination">
            {% if posts.has_previous %}
              <li class="page-item">
                <a href="?page={{ posts.previous_page_number }}" class="page-link">
                  <span>&laquo;</span>
                </a>
              </li>
            {% endif %}

            {% for page_num in posts.paginator.page_range %}
              <li class="page-item {% if page_num == posts.number %} active{% endif %}">
                <a href="?page={{ page_num }}" class="page-link">
                  {{ page_num }}
                </a>
              </li>
            {% endfor %}

            {% if posts.has_next %}
              <li class="page-item">
                <a href="?page={{ posts.next_page_number }}" class="page-link">
                  <span>&raquo;</span>
                </a>
              </li>
            {% endif %}
          </div>
        </div>
      </div>
    </div>
  {% endif %}
{% endblock content %}

The Git Commit