Django proporciona formas de alto nivel y bajo nivel para ayudarte a gestionar datos paginados – es decir, datos divididos en varias páginas con enlaces «Anterior/Siguiente».
Paginator¶Bajo la cubierta, todas las métodos de paginación utilizan la Paginator clase. Ella hace todo el trabajo pesado de dividir realmente un QuerySet en objetos de página Page.
Dale a Paginator una lista de objetos, más el número de elementos que deseas tener en cada página, y te da 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'>
>>> 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
Ten en cuenta que puedes darle a Paginator una lista/tupla, un conjunto de consultas Django o cualquier otro objeto con un método count() o __len__(). Cuando determina el número de objetos contenidos en el objeto pasado, Paginator primero intentará llamar a count(), luego caerá hacia atrás a utilizar len() si el objeto pasado no tiene un método count(). Esto permite que los objetos como Django’s QuerySet utilicen un método de conteo más eficiente cuando esté disponible.
ListView¶django.views.generic.list.ListView proporciona una forma de paginar la lista mostrada de manera integrada. Puedes hacer esto agregando un atributo paginate_by a tu 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 tus usuarios naveguen entre páginas, agrega enlaces a la siguiente y anterior página en tu 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">« 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 »</a>
{% endif %}
</span>
</div>
Paginator en una función de vista¶Aquí tienes un ejemplo usando Paginator en una función de vista para paginar un conjunto de objetos:
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, puedes incluir navegación entre páginas de la misma manera que en la plantilla del ListView anterior.
may 31, 2026