Pagination - csemanish12/flask_blog GitHub Wiki
Right now we are displaying all the posts in our database.Since the number of post is small , there is not issue in scrolling through the posts but when number of post increases, users will have bad experience scrolling through all those posts. We will add pagination to show only limited post in each page.
We will use paginate method for pagination.
posts = Posts.query.paginate(per_page=2, page=1)This will return all the posts in form of pages where each page will have two items and the page number will be 1
lets say there are 11 posts in our database. This will divide those 11 posts in 6 pages where each page will have now 2 posts. The last page will have only one page(as there are only 11 posts).
- to get data from page 4 , we will use "Posts.query.paginate(per_page=2, page=4)"
- similarly, to get data from page 3 , we will use "Posts.query.paginate(per_page=2, page=3)"
we can also change the number of items in each page by modifying "per_page" attribute
Posts.query.paginate(per_page=4, page=1)This will divide our data in 3 pages where each page will have 4 items.
example:(11/4) = 2.7.. = 3 (total number of pages)
Here, paginate method return an object of class Pagination which has following attributes;
- page: the current page that we are in
- total: total number data in that particular class (Post)
- has_next: boolean fields which indicates whether or not there is a next page
- has_prev: boolean fields which indicates whether or not there is a previous page
- items: list of data(in this case, Posts)
- per_page: the number of items in each page
- pages: total number of pages
Lets update our home route to get posts in pages:
blog/routes.py
.
from flask import request
.
@app.route("/")
def home():
page = request.args.get('page', 1, type=int)
posts = Post.query.order_by(Post.date_posted.desc()).paginate(per_page=2, page=page)
return render_template('home.html', posts=posts)We will take page number from user so that they can view the data in that particular page. We will ask input for page using query parameter which flask can access using "request.args.get('variable-name')"
https://localhost:5000/home?page=1here, page is the query parameter that flask can access via request package. To add query parameters in our url, we add question mark(?) at the end of the url.
This will return the posts in pages. so we need to modify our home.html to accommodate this change.
lets update our home.html as follows:
{% extends 'layout.html' %}
{% block content %}
{% for post in posts.items %}
<article class="media content-section">
<img class="rounded-circle article-img" src="{{ url_for('static', filename='profile_pictures/' + post.author.image_file) }}">
<div class="media-body">
<div class="article-metadata">
<a class="mr-2" href="#">{{ post.author.username }}</a>
<small class="text-muted">{{ post.date_posted.strftime('%Y-%m-%d') }}</small>
</div>
<h2><a class="article-title" href="{{ url_for('post', post_id=post.id) }}">{{ post.title }}</a></h2>
<p class="article-content">{{ post.content }}</p>
</div>
</article>
{% endfor %}
{% if posts.has_next and posts.has_prev %}
<a class="btn btn-outline-info mb-4" href="{{ url_for('home', page=posts.page - 1) }}">Previous</a>
<a class="btn btn-info mb-4" href="{{ url_for('home', page=posts.page ) }}">{{ posts.page }}</a>
<a class="btn btn-outline-info mb-4" href="{{ url_for('home', page=posts.page + 1) }}">Next</a>
{% elif posts.has_next %}
<a class="btn btn-info mb-4 ml-4" href="{{ url_for('home', page=posts.page ) }}">{{ posts.page }}</a>
<a class="btn btn-outline-info mb-4" href="{{ url_for('home', page=posts.page + 1) }}">Next</a>
{% elif posts.has_prev %}
<a class="btn btn-outline-info mb-4" href="{{ url_for('home', page=posts.page -1 ) }}">Previous</a>
<a class="btn btn-info mb-4" href="{{ url_for('home', page=posts.page ) }}">{{ posts.page}}</a>
{% else %}
<a class="btn btn-info mb-4" href="{{ url_for('home', page=posts.page - 1) }}">{{posts.page}}</a>
{% endif %}
{% endblock content %}
to get the items from pagination object we will use the ".items" attribute as
for post in posts.items
We will show the user next and previous page based on has_next and has_prev attribute from pagination object which indicates whether or not there are next or previous page, respectively.
Implementation can be found over this commit