Our blog website created with Django is already live on the local server. The only feature we added so far is the comment section as well as a CKEditor which makes it possible to structure our blog page into readable form.
- π€ Part 1: How I Created a Blog Application Using Django
- π€ Part 2: How I Created a Blog Application Using Django
- π€ Part 3: How I Created a Blog Application Using Django
- π€ Part 4: How I Created a Blog Application Using Django
- π€ Part 5: How I Created a Blog Application Using Django
In this fifth part series of this project tutorial, we will include a pagination feature in our blog app. When you hear of pagination, what comes to your mind? The picture below explains it all.
π‘ Pagination is the process of spreading, in this case, your blog content over multiple pages rather than loading them all at once. This is mostly seen in shopping sites with hundreds of products to be displayed. Paginating a web application helps to speed up the page load.
Of course, not everyone fancy having paginated content on their website as finding something specific can be more difficult. Nevertheless, we are going to learn how to add it to our blog application to improve our knowledge of Django.
As always, the documentation is your go-to to learn more.
Django comes with a built-in Paginator
class for paginating content in your application whether you are using a class-based view or a function-based view. If you are using a class-based view, you have to include the .paginate_by
attribute to define the number of blog posts for a given page.
Then, the rest of the attributes including .paginator
, and .page_obj
are added automatically by Django. But if you are using a function-based view, you have to manually add them.
Implementing Pagination in the Blog Application
The view function responsible for displaying a list of posts in our blog is a class-based view. So, letβs see how to implement pagination in the view function. Update the BlogList
class to be like this:
class BlogList(ListView): queryset = Post.objects.filter(status=1).order_by('-created_on') template_name = 'index.html' paginate_by = 2
I choose to have only 2 posts per page given that I have just a few blog articles. But as your blog posts increase, you may decide to increase the number.
Here is the markup we will add to the index.html
. Letβs now go to our template to make the required changes. Remember, we are using Bootstrap to style the web page.
{% if is_paginated %} <nav aria-label="Page navigation container"></nav> <ul class="pagination justify-content-center"> {% if page_obj.has_previous %} <li><a href="?page={{ page_obj.previous_page_number }}" class="page-link">« PREV </a></li> {% endif %} {% if page_obj.has_next %} <li><a href="?page={{ page_obj.next_page_number }}" class="page-link"> NEXT »</a></li> {% endif %} </ul> </nav> </div> {% endif %}
That is exactly what we have to include in the index.html
template. Before we update the markup, letβs first explain what is going on there.
The {% if is_paginated %}
tag checks whether the blog content is paginated. If so, it creates a navigation container using <nav>
and <ul>
elements. The next two if statements check whether there are previous and next pages. If so, it creates a link to those pages using the <a>
element and the href
attribute.
The .previous_page_number
and .next_page_number
methods are used to generate the correct URL for the previous and next pages.
Add the above markup just before the {% endblock %}
tag. Start the local server letβs see it in action.
Can you see it? Our blog post is now paginated by two posts per page. Using the class-based view makes it very easy as everything is done under the hood. We are good to go and call it a day.
A little modification
But what if you want a list of numbers to be displayed rather than the PREV and NEXT? In that case, we have to make a little modification to the markup.
{% if is_paginated %} <nav aria-label="Page navigation container"></nav> <ul class="pagination justify-content-center"> {% for i in page_obj.paginator.page_range %} {% if page_obj.number == i %} <li class="page-item active"><span class="page-link">{{ i }}</span></li> {% else %} <li class="page-item"><a href="?page={{ i }}" class="page-link">{{ i }}</a></li> {% endif %} {% endfor %} </ul> </nav> </div> {% endif %}
The {% for i in page_obj.paginator.page_range %}
tag creates a loop that iterates over the page range, which is the range of page numbers that should be displayed. For each iteration, the value of i
is set to the current page number.
If the current page number is equal to the value of i
, this means that the current page is displayed, a <span>
element is used to display the current page number. Otherwise, a link to the corresponding page is created using the <a>
element.
The drawback to using this method is that it can clutter spaces if the number becomes many. In that case, you can apply any of these options:
- Increase the number of paginated contents from 2 we set above to any number, say 5.
- Do research to find a way to make it appear like this: 1 2 3 β¦ 20.
- Use the first method with PREV and NEXT.
As for me, I prefer the second method to using PREV and NEXT. I will keep using it until my blog post becomes so many.
Conclusion
We have learned how to paginate our blog content using class-based views. If you are using function-based views, you may have to research online to learn other ways to paginate blog content. The source code has been adjusted to reflect the changes we made in this tutorial.
What are we looking forward to in the next series? Adding a sitemap to a blog application is good for search engine optimization. Letβs see if we can give attention to that in part six of this project series. Stay tuned!