15

I'm fairly new to Wagtail, and I am in the process of creating a site that will have a Resources (blog) section and I'm not sure how to implement pagination so that there are only 5 posts on each page and the user has to click a number (1, 2, 3, etc.) to go to the next page to see the next 5 posts.

I have this in my template for the pagination section of the resource/blog index page:

<ul class="pagination">
  <li><a href="#"><i class="fa fa-angle-left"></i></a></li>
  <li class="active"><a href="#">1</a></li>
  <li><a href="#">2</a></li>
  <li><a href="#">3</a></li>
  <li><a href="#"><i class="fa fa-angle-right"></i></a></li>
</ul>

What code do I need to incorporate to make this functional? Thanks in advance.

kbdev
  • 1,225
  • 1
  • 13
  • 33

3 Answers3

24

Django provides the module django.core.paginator for this purpose: https://docs.djangoproject.com/en/1.10/topics/pagination/ . Using this within Wagtail is very similar to the examples in the Django documentation - the only real difference is that when you're setting up the Paginator object to be passed to the template, you do that with a get_context method on the page model, instead of a view function. Your model definition will look something like this:

from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger

class ResourceIndexPage(Page):
    # ...
    def get_context(self, request):
        context = super(ResourceIndexPage, self).get_context(request)

        # Get the full unpaginated listing of resource pages as a queryset -
        # replace this with your own query as appropriate
        all_resources = ResourcePage.objects.live()

        paginator = Paginator(all_resources, 5) # Show 5 resources per page

        page = request.GET.get('page')
        try:
            resources = paginator.page(page)
        except PageNotAnInteger:
            # If page is not an integer, deliver first page.
            resources = paginator.page(1)
        except EmptyPage:
            # If page is out of range (e.g. 9999), deliver last page of results.
            resources = paginator.page(paginator.num_pages)

        # make the variable 'resources' available on the template
        context['resources'] = resources

        return context

Within your template, you can now loop over the items using {% for resource in resources %}, and display the pagination links as follows:

<ul class="pagination">
  {% if resources.has_previous %}
    <li><a href="?page={{ resources.previous_page_number }}"><i class="fa fa-angle-left"></i></a></li>
  {% endif %}
  {% for page_num in resources.paginator.page_range %}
    <li {% if page_num == resources.number %}class="active"{% endif %}><a href="?page={{ page_num }}">{{ page_num }}</a></li>
  {% endfor %}
  {% if resources.has_next %}
    <li><a href="?page={{ resources.next_page_number }}"><i class="fa fa-angle-right"></i></a></li>
  {% endif %}
</ul>
Kalob Taulien
  • 1,817
  • 17
  • 22
gasman
  • 23,691
  • 1
  • 38
  • 56
  • 4
    Just wanted to add that I have used the following around the last `
  • ` to only show the next arrow if there is a next page - `{% if resources.has_next %} {% endif %}` – kbdev Mar 15 '17 at 15:54
  • Nice. This works really well. Is there any way to update this so I can use nice urls that have /page/1/ in? Currently I am hacking around but it's pretty messy! – Designer023 Feb 02 '18 at 13:58
  • 1
    @Designer023 Check out `RoutablePageMixin`: http://docs.wagtail.io/en/v1.13.1/reference/contrib/routablepage.html – gasman Feb 02 '18 at 19:15