Implementación de un paginador personalizado en Django

Código del componente de paginación

class PaginadorPersonalizado: def init(self, pagina_actual, total_registros, ruta_base, query_params, items_por_pagina=8, max_paginas_visibles=11): """ Inicializa los datos de paginación :param pagina_actual: número de página solicitada :param total_registros: cantidad total de registros en la base de datos :param ruta_base: prefijo de URL para los enlaces :param query_params: objeto request.GET :param items_por_pagina: cantidad de elementos por página :param max_paginas_visibles: número máximo de botones de página visibles """ try: pagina_actual = int(pagina_actual) except (TypeError, ValueError): pagina_actual = 1

    if pagina_actual < 1:
        pagina_actual = 1

    self.pagina_actual = pagina_actual
    self.total_registros = total_registros
    self.items_por_pagina = items_por_pagina
    self.ruta_base = ruta_base

    total_paginas, resto = divmod(total_registros, items_por_pagina)
    if resto:
        total_paginas += 1
    self.total_paginas = total_paginas

    self.max_paginas_visibles = max_paginas_visibles
    self.mitad = max_paginas_visibles // 2

    import copy
    params_copiados = copy.deepcopy(query_params)
    params_copiados._mutable = True
    self.params = params_copiados

@property
def indice_inicio(self):
    return (self.pagina_actual - 1) * self.items_por_pagina

@property
def indice_fin(self):
    return self.pagina_actual * self.items_por_pagina

def _calcular_rango(self):
    if self.total_paginas <= self.max_paginas_visibles:
        return 1, self.total_paginas + 1

    if self.pagina_actual <= self.mitad:
        return 1, self.max_paginas_visibles + 1

    if (self.pagina_actual + self.mitad) > self.total_paginas:
        return self.total_paginas - self.max_paginas_visibles + 1, self.total_paginas + 1

    return self.pagina_actual - self.mitad, self.pagina_actual + self.mitad + 1

def generar_html(self):
    inicio, fin = self._calcular_rango()
    elementos = []

    # Botón primera página
    self.params['page'] = 1
    elementos.append('<li><a href="%s?%s">Primera</a></li>' % (self.ruta_base, self.params.urlencode()))

    # Botón página anterior
    if self.pagina_actual <= 1:
        elementos.append('<li class="disabled"><a href="#">Anterior</a></li>')
    else:
        self.params['page'] = self.pagina_actual - 1
        elementos.append('<li><a href="%s?%s">Anterior</a></li>' % (self.ruta_base, self.params.urlencode()))

    # Botones numéricos
    for num in range(inicio, fin):
        self.params['page'] = num
        clase = ' class="active"' if num == self.pagina_actual else ''
        elementos.append('<li><a href="%s?%s">%s</a></li>' % (clase, self.ruta_base, self.params.urlencode(), num))

    # Botón página siguiente
    if self.pagina_actual >= self.total_paginas:
        elementos.append('<li class="disabled"><a href="#">Siguiente</a></li>')
    else:
        self.params['page'] = self.pagina_actual + 1
        elementos.append('<li><a href="%s?%s">Siguiente</a></li>' % (self.ruta_base, self.params.urlencode()))

    # Botón última página
    self.params['page'] = self.total_paginas
    elementos.append('<li><a href="%s?%s">Última</a></li>' % (self.ruta_base, self.params.urlencode()))

    return ''.join(elementos)

paginador.py

</div>Uso desde la vista
------------------

<div>```
from django.shortcuts import render
from .models import Libro
from .utils.paginador import PaginadorPersonalizado


def listar_libros(request):
    pagina = request.GET.get('page', 1)
    total = Libro.objects.count()
    ruta = request.path

    paginador = PaginadorPersonalizado(
        pagina_actual=pagina,
        total_registros=total,
        ruta_base=ruta,
        query_params=request.GET,
        items_por_pagina=8,
        max_paginas_visibles=11
    )

    libros = Libro.objects.all()[paginador.indice_inicio:paginador.indice_fin]

    return render(request, 'listar_libros.html', {'libros': libros, 'paginador': paginador})

vistas.py


listar\_libros.html

</div>El componente copia el objeto `request.GET` utilizando `deepcopy` y lo marca como mutable, lo que permite preservar los parámetros de búsqueda existentes mientras se navega entre páginas. Cada enlace generado incluye automáticamente todos los query strings previos junto con el parámetro `page` actualizado.

</div></body></html>

Etiquetas: Django Paginación Python QueryDict Bootstrap

Publicado el 7-15 05:15