Pagination

View saved

Goal for this part

Stop loading every post on the home page at once. You will read a page number from the query string, ask SQLAlchemy for one slice of results, and render Previous/Next controls.

Pagination matters even for student projects: it keeps pages fast, teaches query parameters, and mirrors how real feeds behave when content grows.

What you should already know

You should already query Post rows and render them in a template loop. Knowing that URLs can carry extra information after ? will help you understand ?page=2.

No advanced SQL is required. Think in terms of “give me five posts, then the next five,” which matches LIMIT and OFFSET ideas from the SQL course.

Concepts: pages, per_page, and query strings

A query string is the part of a URL like ?page=2. Flask can parse it with request.args. Pagination uses that number to choose which slice of an ordered list to show.

per_page controls how many items appear on each page. Teaching snapshots often use a small number such as 5 so you can click through pages without inventing dozens of posts by hand.

Walkthrough: paginate() in the home route

Instead of .all(), call .paginate(...) on the ordered query. Pass the current page, a per_page size, and usually error_out=False so an out-of-range page can degrade gracefully during demos.

The pagination object includes the items for this page plus metadata such as whether a previous or next page exists. Pass both pagination and posts=pagination.items into the template for clarity.

@app.route("/")
def home():
    page = request.args.get("page", 1, type=int)
    pagination = Post.query.order_by(Post.created_at.desc()).paginate(
        page=page,
        per_page=5,
        error_out=False,
    )
    return render_template("home.html", pagination=pagination, posts=pagination.items)

Pager links, seeding, and how to run

In the template, use pagination.has_prev, has_next, and iter_pages to build controls. Each link should call url_for('home', page=...) so Flask generates the correct query string.

This snapshot includes a Flask CLI command seed-demo that inserts a demo user and enough practice posts to fill multiple pages. Run the app, seed once, then click through the pager.

git clone https://github.com/michaeldunga1/fcc-flask-blog.git
cd fcc-flask-blog/07-Pagination
python3 -m venv .venv
source .venv/bin/activate
pip install -r ../requirements.txt
python app.py
# optional:
flask --app app seed-demo

Common mistakes and troubleshooting

If every page shows the same posts, you may still be calling .all() or ignoring the page argument. If links 404 or look wrong, confirm you pass page into url_for and that the route still listens on /.

Empty pages after seeding often mean you seeded a different database file than the running app uses, or you need to restart after changing environment variables.

Try this checklist

  • Seed demo data and confirm more than one page exists
  • Open /?page=2 directly and verify the posts change
  • Use Previous/Next until you reach the ends of the feed
  • Temporarily set per_page to 3 and watch the page count grow

Next: Deploy

Comments

One comment per signed-in account. Comments are saved with this page’s URL.