Las tres formas que trae DRF, la fila que aparece dos veces al recorrer un listado, y el contador que cuesta una consulta por página.
⏱ 15 min de lectura
La lección 9 vio la paginación desde el lado de quien consume una API, con sus tres estilos y sus problemas. Ahora toca elegir cuál ofreces, y las consecuencias son tuyas.
La lección 12 dejó dicho que la paginación se activa el primer día, porque cambia la forma de la respuesta. Aquí va la elección de cuál.
from rest_framework.pagination import(
CursorPagination, LimitOffsetPagination, PageNumberPagination)classPaginaNumerada(PageNumberPagination):
page_size =20
page_size_query_param ='tam'# deja al cliente pedir otro tamaño
max_page_size =100# y le pone topeclassPorDesplazamiento(LimitOffsetPagination):
default_limit =20
max_limit =100classPorCursor(CursorPagination):
page_size =20
ordering ='-creado'# obligatorio, y tiene que ser estable
Lo que devuelve cada una:
Salida en pantalla
--- por número ---
count: 201
next: http://.../api/libros/?page=2
previous: None
results: 20 elementos
--- por desplazamiento ---
count: 201
next: http://.../api/libros/?limit=20&offset=20
previous: None
results: 20 elementos
--- por cursor ---
next: http://.../api/libros/?cursor=cD0yMDI2LTA5LTIyKzE5JTNBMTUlM0EyMS4xMDU4NzQ...
previous: None
results: 20 elementos
La de cursor no tiene count. Es la primera diferencia y es deliberada: contar es lo que cuesta.
Y el cursor, descodificado, no es un número de página:
Es la posición del último elemento devuelto. Va en base64 no para esconderlo sino para que quepa en una dirección, y eso explica todas sus propiedades: no se puede saltar a la página cincuenta, y no se puede desincronizar.
por número 3 consultas, de ellas 1 es un COUNT
por desplazamiento 3 consultas, de ellas 1 es un COUNT
por cursor 2 consultas, ninguna es un COUNT
Esa consulta de más es el count de la respuesta, y es una consulta entera por cada página que sirvas. Con una tabla pequeña no se nota; con millones de filas, contar puede tardar más que traer la página.
Y con filtros es peor, porque el contador cuenta las filas filtradas: no vale cachearlo.
Ese es el intercambio, y hay que decidirlo sabiendo que el contador se usa para pintar una barra de progreso y poco más.
Por número para lo que tiene interfaz de usuario con páginas numeradas y no cambia cada segundo: un catálogo, un archivo, un listado administrativo.
Por desplazamiento es lo mismo con otra sintaxis, y lo único que añade es que el cliente controle el tamaño con más naturalidad. Tiene el mismo problema de estabilidad.
Por cursor para cualquier cosa que se recorra entera, que cambie a menudo o que sea grande: un registro de eventos, una cola de mensajes, una sincronización, una línea de tiempo. Y para tablas de millones de filas, donde la diferencia de coste es abismal:
Con desplazamiento, OFFSET 100000 obliga a la base de datos a generar y descartar cien mil filas antes de devolver las veinte que quieres. Con cursor, es una búsqueda por índice: cuesta lo mismo en la página 1 que en la 5000.
La respuesta práctica para muchos proyectos es las dos: por número en el recurso que consume tu propia interfaz, y por cursor en un punto de acceso pensado para recorrer.