Pagination in Django ListView when using get_context_data

Question:

I am currently facing this problem with Django ListView. Basically, I need to filter some questions per topic and I would like to paginate the results.
My code is working perfectly about the queryset part (the results are showed correctly) but I am facing a problem with pagination.
Let’s say I have so far 8 items in my query, if I choose to paginate_by = 10, it shows me just one page. If, otherwise, I choose to paginate by, let’s say, 3, it shows me 3 pages to choose in the template (which is correct) but it shows me ALL the results of the query in my page.
I post some code to be more clear

models.py:

class Tag(models.Model):
name = models.CharField(max_length=300, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

def clean(self):
    self.name = self.name.capitalize()

def __str__(self):
    return self.name


class Question(models.Model):
    post_owner = models.ForeignKey(User, on_delete=models.CASCADE)
    title = models.CharField(max_length=5000, default='')
    body = tinymce_models.HTMLField()
    tags = models.ManyToManyField(
        Tag, related_name='tags')
    viewers = models.ManyToManyField(
        User, related_name='viewed_posts', blank=True)

views.py:

class TagQuestionsListView(ListView):
template_name = 'main/tag_questions.html'
paginate_by = 20

def get_queryset(self, **kwargs):
    tag = Tag.objects.get(name=self.kwargs['name'])
    questions = Question.objects.filter(tags=tag)
    return questions

def get_contextdata(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context['tag'] = Tag.objects.get(name=self.kwargs['name'])
    context['questions'] = Question.objects.filter(
        tags=context['tag'], is_deleted=False)
    return context

template:

{% extends 'base.html' %}
{% load humanize %}
{% block title %}Domande su {{tag.name}}{% endblock title %}
{% block content %}
<style>
    .text {
        overflow: hidden;
        text-overflow: ellipsis;
        display: -webkit-box;
        -webkit-line-clamp: 2; /* number of lines to show */
                line-clamp: 2; 
        -webkit-box-orient: vertical;
     }
</style>
<div class="card">
    <div class="mt-3">
        <h3 class="ms-2" style="display: inline;">Ultime {{ questions.count }} Domande</h3>
        {% if request.user.is_authenticated %}
        <a href="{% url 'main:new_question' %}" class="btn btn-primary float-end me-3" style="display: inline;">Fai una domanda</a>
        {% else %}
        <a href="{% url 'account:login_user' %}" class="btn btn-primary float-end me-3" style="display: inline;">Fai una domanda</a>
        {% endif %}
    </div>  
    <h5 class="ms-2">{{ total_questions.count }} domande totali </h5>
    <hr>
    {% for question in questions %}
    <div class="row">
        <div class="col-2 ms-2">
            <p>{{ question.count_all_the_votes }} Voti</p>
            <p>{{ question.count_answers }} Risposte</p>
            <p>{{ question.calculate_viewers }} Visualizzazioni</p>
        </div>
        <div class="col-9">
            <a href="{% url 'main:question_details' pk=question.id slug=question.slug %}"><h5>{{question.title}}</h5></a>
            <div class="text">
                {{ question.body|striptags }}
            </div>
            {% for tag in question.tags.all %}
            <a class="btn btn-sm btn-outline-primary m-1" href="{% url 'main:tag_questions' name=tag.name %}">{{tag.name}}</a>
            {% endfor %}
            <div class="float-end">
                <a style="display: inline;" href="">{{question.post_owner}}</a> 
                {% if question.is_edited == False %}
                <span style="display:inline;">creata {{question.created_at | naturaltime}}</span>
                {% else %}
                <span style="display:inline;"> modificata {{question.edited_time | naturaltime}} da <a style="display: inline;" href="">{{question.edited_by.username}}</a></span>
                {% endif %}
            </div>
        </div>
    </div>
    <hr>
    {% endfor %}
</div>
<div class="row mt-3">
    <div class="col-lg-12">
    <div class="card">
      <div class="card-body">
        <nav aria-label="Page navigation example">
          <ul class="pagination">
            {% if page_obj.has_previous %}
            <li class="page-item"><a class="page-link" href="{% url 'main:tag_questions' name=tag.name %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.previous_page_number }}">Precedente</a></li> 
            {% else %}
            <li class="page-item disabled"><a class="page-link" href="#">Precedente</a></li>            
            {% endif %}
            {% for i in paginator.page_range %}
            <li class="page-item {% if page_obj.number == i%} active {% endif %} %} "><a class="page-link" href="?filter={{ filter }}&orderby={{ orderby }}&page={{ i }}">{{i}}</a></li>
            {% endfor %}
            {% if page_obj.has_next %}
            <li class="page-item"><a class="page-link" href="{% url 'main:tag_questions' name=tag.name %}?filter={{ filter }}&orderby={{ orderby }}&page={{ page_obj.next_page_number }}">Prossima</a></li> 
            {% else %}
            <li class="page-item disabled"><a class="page-link" href="#">Prossima</a></li>            
            {% endif %}
          </ul>
        </nav>
      </div>
    </div>
  </div>

{% endblock content %}
Asked By: Giorgio Scarso

||

Answers:

With this I want my comment converter to answer.

You have to use page_obj instead questions in your template.

<--!               ⬇️⬇️⬇️      -->
{% for question in page_obj %}
<div class="row">
    <div class="col-2 ms-2">
        <p>{{ question.count_all_the_votes }} Voti</p>
        <p>{{ question.count_answers }} Risposte</p>
        <p>{{ question.calculate_viewers }} Visualizzazioni</p>
    </div>
    <div class="col-9">
        <a href="{% url 'main:question_details' pk=question.id slug=question.slug %}"><h5>{{question.title}}</h5></a>
        <div class="text">
            {{ question.body|striptags }}
        </div>
        {% for tag in question.tags.all %}
        <a class="btn btn-sm btn-outline-primary m-1" href="{% url 'main:tag_questions' name=tag.name %}">{{tag.name}}</a>
        {% endfor %}
        <div class="float-end">
            <a style="display: inline;" href="">{{question.post_owner}}</a> 
            {% if question.is_edited == False %}
            <span style="display:inline;">creata {{question.created_at | naturaltime}}</span>
            {% else %}
            <span style="display:inline;"> modificata {{question.edited_time | naturaltime}} da <a style="display: inline;" href="">{{question.edited_by.username}}</a></span>
            {% endif %}
        </div>
    </div>
</div>
<hr>
{% endfor %}

So, if you define attribute paginate_by , than ListView(django docs) adds a paginator and page_obj to the context. To allow the users to navigate between pages, add links to the next and previous page, in your template.

Answered By: NKSM
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.