Django proporciona formas de alto y bajo nivel para ayudarlo a administrar datos paginados, es decir, datos que se dividen en varias páginas, con enlaces “Anterior / Siguiente”.

los Paginator clase

Bajo el capó, todos los métodos de paginación usan el Paginator clase. Hace todo el trabajo pesado de dividir un QuerySet dentro Page objetos.

Ejemplo

Dar Paginator una lista de objetos, más la cantidad de elementos que le gustaría tener en cada página, y le brinda métodos para acceder a los elementos de cada página:

>>> from django.core.paginator import Paginator
>>> objects = ['john', 'paul', 'george', 'ringo']
>>> p = Paginator(objects, 2)

>>> p.count
4
>>> p.num_pages
2
>>> type(p.page_range)
<class 'range_iterator'>
>>> p.page_range
range(1, 3)

>>> page1 = p.page(1)
>>> page1
<Page 1 of 2>
>>> page1.object_list
['john', 'paul']

>>> page2 = p.page(2)
>>> page2.object_list
['george', 'ringo']
>>> page2.has_next()
False
>>> page2.has_previous()
True
>>> page2.has_other_pages()
True
>>> page2.next_page_number()
Traceback (most recent call last):
...
EmptyPage: That page contains no results
>>> page2.previous_page_number()
1
>>> page2.start_index() # The 1-based index of the first item on this page
3
>>> page2.end_index() # The 1-based index of the last item on this page
4

>>> p.page(0)
Traceback (most recent call last):
...
EmptyPage: That page number is less than 1
>>> p.page(3)
Traceback (most recent call last):
...
EmptyPage: That page contains no results

Nota

Tenga en cuenta que puede dar Paginator una lista / tupla, un Django QuerySet, o cualquier otro objeto con un count() o __len__() método. Al determinar el número de objetos contenidos en el objeto pasado, Paginator primero intentará llamar count(), luego vuelva a usar len() si el objeto pasado no tiene count() método. Esto permite que objetos como los de Django QuerySet para usar un más eficiente count() método cuando esté disponible.

Paginar un ListView

django.views.generic.list.ListView proporciona una forma integrada de paginar la lista mostrada. Puede hacer esto agregando un paginate_by atributo a su clase de vista, por ejemplo:

from django.views.generic import ListView

from myapp.models import Contact

class ContactListView(ListView):
    paginate_by = 2
    model = Contact

Esto limita el número de objetos por página y agrega un paginator y page_obj al context. Para permitir que sus usuarios naveguen entre páginas, agregue enlaces a la página anterior y siguiente, en su plantilla de esta manera:

{% for contact in page_obj %}
    {# Each "contact" is a Contact model object. #}
    {{ contact.full_name|upper }}<br>
    ...
{% endfor %}

<div class="pagination">
    <span class="step-links">
        {% if page_obj.has_previous %}
            <a href="?page=1">&laquo; first</a>
            <a href="?page={{ page_obj.previous_page_number }}">previous</a>
        {% endif %}

        <span class="current">
            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 &raquo;</a>
        {% endif %}
    </span>
</div>

Utilizando Paginator en una función de vista

Aquí hay un ejemplo usando Paginator en una función de vista para paginar un conjunto de consultas:

from django.core.paginator import Paginator
from django.shortcuts import render

from myapp.models import Contact

def listing(request):
    contact_list = Contact.objects.all()
    paginator = Paginator(contact_list, 25) # Show 25 contacts per page.

    page_number = request.GET.get('page')
    page_obj = paginator.get_page(page_number)
    return render(request, 'list.html', {'page_obj': page_obj})

En la plantilla list.html, puede incluir la navegación entre páginas de la misma forma que en la plantilla para el ListView encima.