Pagination

View saved

Goal for this part

Keep Campus Press readable as posts grow. You will paginate the home list (and often an author’s post list) so each page shows a fixed number of entries with next/previous links.

After this snapshot, adding many posts should no longer dump everything onto a single scrolling page.

What you should already know

You should have a working home queryset of posts. If you use ListView, pagination settings are a few attributes; function views can use Paginator directly.

Query parameters like ?page=2 tell Django which slice to show. Templates read page_obj for controls.

Concepts: page objects and ListView

paginate_by on a ListView instructs Django to paginate the queryset automatically and provide page_obj in the context. Invalid page numbers should fail softly—Django’s defaults handle many cases.

Author pages can reuse the same idea with a filtered queryset, so each writer’s archive paginates independently.

from django.views.generic import ListView
from .models import Post

class PostListView(ListView):
    model = Post
    template_name = "blog/home.html"
    context_object_name = "posts"
    ordering = ["-date_posted"]
    paginate_by = 5

Walkthrough: pagination controls in the template

Render previous/next links when page_obj.has_previous or has_next is true. Show the current page number so readers know where they are. Keep surrounding query parameters in mind if you add filters later.

{% if is_paginated %}
  {% if page_obj.has_previous %}
    <a href="?page=1">First</a>
    <a href="?page={{ page_obj.previous_page_number }}">Prev</a>
  {% endif %}
  <span>Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}</span>
  {% if page_obj.has_next %}
    <a href="?page={{ page_obj.next_page_number }}">Next</a>
    <a href="?page={{ page_obj.paginator.num_pages }}">Last</a>
  {% endif %}
{% endif %}

How to run it and what you should see

Run 10-Pagination, seed or create more than one page of posts, and click through the controls. Page size in the snapshot is small on purpose so you do not need dozens of entries.

git clone https://github.com/michaeldunga1/fcc-django-blog.git
cd fcc-django-blog/10-Pagination
python3 -m venv .venv
source .venv/bin/activate
pip install -r ../requirements.txt
python manage.py migrate
python manage.py runserver

Common mistakes and troubleshooting

If pagination links 404, confirm the list route accepts the page query param (it should by default). If all posts still show on one page, paginate_by may be unset or the template may still iterate a non-paginated context variable.

Empty pages at high numbers usually mean you requested past the end—use the paginator’s page count when linking to “Last”.

Try this

Change paginate_by to 2, restart, and recount the pages. Then open an author filter page (if present) and confirm it paginates separately from home.

  • Paginate early—feeds grow faster than you expect
  • Use page_obj helpers in templates
  • Keep ordering stable so pages do not shuffle randomly

Next: Password Reset

Comments

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