Richard
Posted on August 9, 2020
This is part 4 of the Django Diaries, we will look at implementing Pagination in Django.
The code from Corey Schafer's Tutorial can be found here (Number 11). This blog series is entirely based on what I learned from here:
Django has pagination sorted for us, we just need to implement the buttons and set some attributes.
Example
For this example I will open the django shell with python manage.py shell
>>> from django.core.paginator import Paginator
>>> posts = ['1','2','3','4','5','6','7','8','9','10']
# Posts is our object of posts and 2 is the number of posts per page
>>> p = Paginator(posts,2)
# Return the number of pages in this case we have 10 post with 2
# per page, so 10/2
>>> p.num_pages
5
# page_range is an object of pages
>>> for page in p.page_range:
... print(page)
1
2
3
4
5
# Get specific page
>>> p1 = p.page(1)
>>> p1
<Page 1 of 5>
# get page number
>>> p1.number
1
# get all the posts on that page
>>> p1.object_list
['1','2']
# Check for previous and next pages
>>> p1.has_previous()
False
>>> p1.next_page_number()
2
Creating a Paginator
For paginating our blog post app, we need to specify some attributes in the view.
class PostListView(ListView):
model = Post
template_name = "blog/home.html"
context_object_name = 'posts'
ordering = ['-date_posted']
# Add Django Pagination
paginate_by = 4
Now the Paginator knows now many posts should be on each page, simply by adding a 'paginate_by' attribute, because we are using a class based view we don't actually need to import paginator. That's the pagination done. I set 'paginate_by' to four as I want 4 posts per page.
If we reload the server and visit '/?page=2' we should see the next page being loaded. All we need to do now is to add links to the next page in our templates.
Adding buttons to the template
For this I will use a Bootstrap button group.
Here we check if there is a Paginator active. Then we add the First and Previous Page links. We Check if there is a previous page, and then set a link to page 1 by setting the page to 1. We can then access the page object using page_obj
to get the previous page number and link to that.
We do the same to add buttons for the next and last page. Notice we are setting the last page number to the number of pages; because if we have 25 pages then the last page will be number 25.
Finally we loop over the number of pages to create a link for a couple of pages around the current page. So if we are on page six we have links to 7,8,9 and 5,4,3 just so we don't have all the numbers showing.
We create a for loop to loop over all the pages. Then we add a button for the current page with different styles, using a condition to check if the loop value is the current page. We then print a few pages around the current page using django filters, so we check if the current number is > 3 pages bellow the current page and < 3 pages after. (This all goes in the is paginated conditional)
Here you can see that other pages are displayed around the current page, I only have 3 pages so we don't see 3 up and 3 down.
Adding links for user specific posts
Now we would like to see all of one users posts when we click on their name.
In order to modify the results of a query from a view we can define a method called get_queryset()
For this I will create a new view.
from django.shortcuts import get_object_or_404
from django.contrib.auth.models import User
class UserPostListView(ListView):
model = Post
template_name = "blog/user_post.html"
context_object_name = 'posts'
paginate_by = 4
# over ride query
def get_queryset(self):
user = get_object_or_404(User, username=self.kwargs.get("username"))
return Post.objects.filter(author=user).order_by('-date_posted')
We have created a new list view, and defined a get_queryset method. Now we can use a django shortcut called get_object_or_404 to make user the user exists. We get the username from the url using self.kwargs.get('username')
. Kwargs refers to the keyword arguments from the url. We then filter the posts be author and reorder then because we are overiding the query.
Finally add this to urls.py
path("user/<str:username>", UserPostListView.as_view(), name="user-posts")
Last but not least we need to make a user_post
template, as that's what we called it in the view. For this we can just copy the home template as it will be very similar. I will add a conditional on top to display the users name or 'Your Posts' of the user is looking at their own posts.
We will also add links in all templates to go to the users posts.
Thank you for reading part 4. Up next is the finally part where we will send emails to reset a users password.
DISCLAIMER: This is all from Corey Schafters Tutorial series, I you want to build this project I highly recommend you check out the videos If you want to build this yourself.
✨If you would like to follow my day to day development journey be sure to check my Instagram.
Posted on August 9, 2020
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.