Pagination
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_objhelpers 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.