Search code examples
jsondjangopaginationcs50

Why paginating a ListView in django does not work?


I am doing the CS50W, the Network project, when I want to move to next / go back to the pagination of my web. Nothing happened. I tried to debug the view.py file, anytime I click the next or previous button in script.js , it all returned page_number as none in views.py . I have no idea why this happened. Can you guys help me?

Here are the code in my views.py :

def index(request):
    return render(request, "network/index.html")

def allPosts(request):
    # Get all posts data - json
    allPosts = Post.objects.all()
    # Return emails in reverse chronologial order
    allPosts = allPosts.order_by("-timestamp").all()
    # Show 2 contacts per page.
    paginator = Paginator(allPosts, 2) 
    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    # return json all posts
    data = {
        'posts': [post.serialize() for post in page_obj],
        'page': {
            'has_previous': page_obj.has_previous(),
            'previous_page': page_obj.has_previous() and page_obj.previous_page_number() or None,
            'has_next': page_obj.has_next(),
            'next_page': page_obj.has_next() and page_obj.next_page_number() or None,
            'num_pages' : page_obj.paginator.num_pages,
            'current_page' : page_number
        }
    }
    return JsonResponse(data, safe=False)

Code in my script.js file:

document.addEventListener('DOMContentLoaded', function() {
    // Use buttons to toggle between views
    document.querySelector('.showallPosts').addEventListener('click',showallPosts);
    showallPosts();
  });

  function showallPosts(){
    // Clear out composition field
    document.querySelector('#allPosts-view').value = '';
    // Show the mailbox name
    document.querySelector('#allPosts-view').innerHTML = `
        <h3>All Posts</h3>
    `;
    // Get data
    fetch(`/allPosts`)
    .then(response => response.json())
    .then(result => {
      //Process to get data
      for(let i = 0; i < result.posts.length; i++) {
        const newDiv = document.createElement('div');
        newDiv.classList.add('list-group-item');
        let post = result.posts[i];
        let post_timestamp = post.timestamp;
        let post_author = post.author;
        let post_content = post.content;
        let post_likes = post.likes;
        newDiv.innerHTML = `
          <h5>Author: ${post_author}</h5>
          <h6>At: ${post_timestamp}</h6>
          <p>Has wrote: ${post_content}</p>
          <p><strong>Likes</strong>: ${post_likes}</p>
        `;
        document.querySelector('#allPosts-view').append(newDiv);
      }
      page = result.page;
      const toggleDiv = document.createElement('div');
      toggleDiv.classList.add('pagination');
      if (page.has_previous) {
        toggleDiv.innerHTML = `
            <a href="?page=1">&laquo; first</a>
            <a href="?page=${page.previous_page}">previous</a>
        `;
      }
      if (page.has_next) {
        toggleDiv.innerHTML += `
          <a href="?page=${page.next_page}">next</a>
          <a href="?page=${page.num_pages}">last &raquo;</a>
        `;
      }
      document.querySelector('#toggle').append(toggleDiv);
    })
  }

My urls.py file:


from django.urls import path

from . import views

urlpatterns = [
    path("", views.index, name="index"),
    path("login", views.login_view, name="login"),
    path("logout", views.logout_view, name="logout"),
    path("register", views.register, name="register"),
    path("createPost", views.createPost, name="createPost"),
    path("allPosts", views.allPosts, name="allPosts")
]

I expect the page to display other posts, but no. It is always the first page of the pagination.


Solution

  • You always fetch without a page parameter. Indeed:

    fetch(`/allPosts`)

    You don't add a ?page= parameter, so it will always fetch data of the first page.

    You should look for a ?page= parameter in the page, and add this to the fetch request, like:

    const searchParams = new URLSearchParams(window.location.search);
    fetch(`/allPosts?` + new URLSearchParams({
        page: searchParams.get('page') || 1
    }))