Desde hace ya un tiempo que comencé con Django a hacer todo tipo de cosas, de ideas que puedes consultar en este Blog y en mi canal de Youtube, y me di cuenta que faltan algunos elementos básicos que todavía tenemos que ver, que no pueden ser otros que la paginación.
Para paginar en Django lo podemos hacer con una sencilla clase llamada Paginator, como puedes ver en los ejemplos de esta publicacion, el truco aqui es saber que existen dos tipos de vistas en Django, las genéricas, empleando para este particular caso los ListView, que por supuesto también los podemos paginar, y las vistas personalizadas que es la que vamos a ver en esta entrada
Paginación del lado de la vista y el template
Vamos a paginar en ambos lados, en un lado, el cliente o la página web, desplegar el listado, colocarlo bonito, con CSS con Bootstrap en este caso, aunque puedes emplear CSS personalizado, Bulma, Tailwind, o cualquier cosa con la que trabajes.
Vamos a aprender a cómo podemos crear un sencillo sistema de paginación bastante genérico y reutilizable para nuestro listado.
Esto es una práctica bastante común hoy en día que queremos hacer una paginación de un listado o tal de registros, como publicaciones de un post, un listado de productos para una tienda en línea etc.
Paginación en Django en cualquier vista
Siguiendo nuestro ejemplo vamos a crear un sencillo sistema de paginación para los comentarios; para esto vamos a seguir con el código que mostramos anteriormente:
Paginación en Django
En Django tenemos una clase llamada Paginator la cual recibe dos argumento, el listado de todos los registros, y el nivel de paginación, es decir, si quieres una página con 5 registros (tamaño de la página 5) 10, etc.
Como puedes ver, también validamos que recibimos un parámetro vía get para indicar que pagina queremos ver, en este caso vamos a emplear el parámetro que viaja via get, llamado page, pero puede tener cualquier nombre; recuerda colocar alguna validación para evitar problemas y que maneje un rango correspondiente:
page_number = request.GET.get('page')
Así que, con la clase Paginator de Django le pasamos cuales es el listado que queremos paginar y el nivel de paginación; el resto del código queda igual que la entrada anterior:
comments = Comment.objects.all()
paginator = Paginator(comments, 5) # Show 25 contacts per page.
page_number = request.GET.get('page')
comments_page = paginator.get_page(page_number)
return render(request,'index.html',{'comments_page': comments_page})
Generar los enlaces o links para la paginación
El código principal sería exactamente el mismo que el empleado anteriormente, pero ahora vamos a agregar algunos enlaces de paginación; como puedes ver, para crear un esquema reutilizable, estamos incluyendo una vista, que vienen siendo la de los enlaces de navegación:
<body>
{% for c in comments_page %}
<div>
<p>
{{ c.text|escape }}
{{ c.date_posted|date:"D d M Y" }}
</p>
</div>
{% endfor %}
{% include "partials/pagination.html" with page_obj=comments_page %}
</body>
Construir los enlaces de paginación con diseño de Bootstrap 4 o 5
La vista para generar los enlaces la vamos a guardar en la siguiente ubicación como pudiste ver en el código anterior:
partials/pagination.html
Esta vista simplemente va a recibir el listado completo de registros que queremos paginar; el código en si no tiene nada de complicado, simplemente verificar si tenemos enlaces anteriores o posteriores y finalmente iterar según el rango de paginación que tengamos para generar los enlaces de paginación:
<nav aria-label="Page navigation example">
<ul class="pagination justify-content-center mt-5">
{% if page_obj.has_previous %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.previous_page_number }}">previous</a>
</li>
{% endif %}
{% for i in page_obj.paginator.page_range %}
{% if i == page_obj.number %}
<li class="page-item active">
<a class="page-link" href="#">{{ i }}</a>
</li>
{% else %}
<li class="page-item">
<a class="page-link" href="?page={{ i }}">{{ i }}</a>
</li>
{% endif %}
{% endfor %}
{% if page_obj.has_next %}
<li class="page-item">
<a class="page-link" href="?page={{ page_obj.next_page_number }}">next</a>
</li>
{% endif %}
</ul>
</nav>
El código aunque parezca complicado si lo analizas un poco se auto explica solo, simplemente queremos construir enlaces de navegación, tenemos dos condicionales, al inicio y final del bloque simplemente para preguntar si existen enlaces previos o siguientes a mostrar; y en el medio, pintamos todos los enlaces de navegación.
Explicacion de parametros empleados
Empleamos varios parámetros en la vista para construir nuestros enlaces de navegación:
- page_obj.has_previous: Booleano que indica si hay una página anterior.
- page_obj.has_next: Booleano que indica si hay una página posterior.
- page_obj.previous_page_number: Devuelve el número de la página anterior.
- page_obj.next_page_number: Devuelve el número de la siguiente página.
- page_obj.number: Devuelve el número de la página actual.
- page_obj.paginator.num_pages: Devuelve el número total de páginas.
Extra: Paginación en Django con ListView
También podemos emplear el esquema de paginación empleando las vistas genéricas que nos ofrece Django; específicamente la vista genérica ListView, para las listas.
Tenemos que definir simplemente una clase que extienda de ListView y especificar algunos parámetros:
- El modelo con el cual vamos a trabajar
- La ubicación del template, que perfectamente podemos emplear el del listado anterior
- El nivel de paginación.
Además de esto, tenemos que crear una función llamada get_queryset la cual recibe como parámetro la página y tenemos que devolver una instancia de la página actual.
Así que con esto, nuestro código queda de la siguiente manera:
from django.views.generic import ListView
from django.core.paginator import Paginator
class Comentarios(ListView):
model = Comment
template_name = 'index.html'
paginate_by = 3
def get_queryset(self,pag=1):
comments = Comment.objects.all()
paginacion = Paginator(comments,'cantidad objetos')
if len(paginacion.page(1)) == 0:
return None
else:
return paginacion.page(pag)
El parámetro que vamos a pasarle al template se llama objet_list, por lo tanto, tenemos que cambiar la referencia en el template:
{% for c in object_list %}
Conclusiones
La paginación es un esquema que empleamos en cualquier framework moderno como hoy en día y al día día no puede faltar para poder paginar distintos tipos de desarrollo que queramos hacer, ya sea para emplearlos en una tabla, u otro elemento personalizable inclusive una RestApi.
Por supuesto, Django al manejar distintos tipos de templates, podemos definir la misma para cada tipo de template, ya sea en el uso de los ListViem como componente de vistas genéricas o una vista/template 100% personalizable por nosotros y todo girando con el queryset que viene siendo nuestra fuente de datos.
Por supuesto, Django al manejar distintos tipos de templates, podemos definir la misma para cada tipo de template, ya sea en el uso de los ListViem como componente de vistas genéricas o una vista/template 100% personalizable por nosotros.
![Andrés Cruz Andrés Cruz](/public/images/perfil.jpg)
Desarrollo con Laravel, Django, Flask, CodeIgniter, HTML5, CSS3, MySQL, JavaScript, Vue, Android, iOS, Flutter