En la parte anterior de esta serie, vimos cómo implementar Edit
y Delete
funcionalidad deseada para nuestra aplicación de lista de deseos. En esta parte, implementaremos la funcionalidad de paginación para nuestra lista de inicio de usuarios.
Cómo empezar
Empecemos clonando la parte anterior del tutorial de GitHub.
git clone https://github.com/jay3dec/PythonFlaskMySQLApp_Part4.git
Una vez que se haya clonado el código fuente, navegue hasta el directorio del proyecto e inicie el servidor web.
cd PythonFlaskMySQLApp_Part4 python app.py
Apunte su navegador a http://localhost:5002/ y debería tener la aplicación ejecutándose.
Implementación de paginación
A medida que aumenta la lista de deseos en la página de inicio del usuario, se desplaza hacia abajo en la página. Por lo tanto, es importante implementar la paginación. Limitaremos la cantidad de elementos que se muestran en una página a un número determinado.
Modificar el procedimiento Obtener deseo
Comenzaremos modificando el sp_GetWishByUser
procedimiento para devolver resultados basados en un limit
y offset
valor. Esta vez crearemos nuestra declaración de procedimiento almacenado dinámicamente para devolver el conjunto de resultados en función del límite y el valor de compensación. Aquí está el sp_GetWishByUser
modificado Procedimiento almacenado de MySQL.
USE `BucketList`; DROP procedure IF EXISTS `sp_GetWishByUser`; DELIMITER $$ USE `BucketList`$$ CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_GetWishByUser`( IN p_user_id bigint, IN p_limit int, IN p_offset int ) BEGIN SET @t1 = CONCAT( 'select * from tbl_wish where wish_user_id = ', p_user_id, ' order by wish_date desc limit ',p_limit,' offset ',p_offset); PREPARE stmt FROM @t1; EXECUTE stmt; DEALLOCATE PREPARE stmt1; END$$ DELIMITER ;
Como se ve en el procedimiento almacenado anterior, creamos nuestra consulta SQL dinámica y la ejecutamos para obtener la lista de deseos basada en el offset
y limit
parámetros.
Agregar paginación a la IU
Primero, definamos algunas configuraciones predeterminadas. En app.py
agregue una variable para el límite de páginas.
# Default setting pageLimit = 2
Haz el getWish
El método Python acepta solicitudes POST.
@app.route('/getWish',methods=['POST'])
Leer el offset
y limit
dentro de getWish
y páselo mientras llama al procedimiento almacenado de MySQL sp_GetWishByUser
.
_limit = pageLimit _offset = request.form['offset'] con = mysql.connect() cursor = con.cursor() cursor.callproc('sp_GetWishByUser',(_user,_limit,_offset)) wishes = cursor.fetchall()
Modifica el GetWishes
Función JavaScript en userHome.html
para convertirlo en una solicitud POST y pasar el offset
valor.
function GetWishes() { $.ajax({ url: '/getWish', type: 'POST', data: { offset: 0 }, success: function(res) { var wishObj = JSON.parse(res); $('#ulist').empty(); $('#listTemplate').tmpl(wishObj).appendTo('#ulist'); }, error: function(error) { console.log(error); } }); }
Guarde todos los cambios y reinicie el servidor. Inicie sesión con una dirección de correo electrónico y una contraseña válidas y solo debería mostrar dos registros en la pantalla.
Entonces, la parte de la base de datos está funcionando bien. A continuación, debemos agregar la interfaz de usuario de paginación a la página de inicio del usuario, lo que permitirá al usuario navegar por los datos.
Usaremos el componente de paginación Bootstrap. Abra userHome.html
y agregue el siguiente código HTML después de #ulist
UL.
<nav> <ul class="pagination"> <li> <a href="#" aria-label="Previous"> <span aria-hidden="true">«</span> </a> </li> <li><a href="#">1</a> </li> <li><a href="#">2</a> </li> <li><a href="#">3</a> </li> <li><a href="#">4</a> </li> <li><a href="#">5</a> </li> <li> <a href="#" aria-label="Next"> <span aria-hidden="true">»</span> </a> </li> </ul> </nav>
Guarde los cambios y reinicie el servidor. Después de iniciar sesión con éxito, debería poder ver la paginación debajo de la lista de deseos.
Dinamización de la paginación
La paginación anterior es cómo se verá nuestra paginación. Pero para que sea funcional, necesitamos crear nuestra paginación dinámicamente en función de la cantidad de registros en la base de datos.
Para crear nuestra paginación, necesitaremos el número total de registros disponibles en la base de datos. Así que modifiquemos el procedimiento almacenado de MySQL sp_GetWishByUser
para devolver el número total de registros disponibles como parámetro de salida.
USE `BucketList`; DROP procedure IF EXISTS `sp_GetWishByUser`; DELIMITER $$ USE `BucketList`$$ CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_GetWishByUser`( IN p_user_id bigint, IN p_limit int, IN p_offset int, out p_total bigint ) BEGIN select count(*) into p_total from tbl_wish where wish_user_id = p_user_id; SET @t1 = CONCAT( 'select * from tbl_wish where wish_user_id = ', p_user_id, ' order by wish_date desc limit ',p_limit,' offset ',p_offset); PREPARE stmt FROM @t1; EXECUTE stmt; DEALLOCATE PREPARE stmt; END$$ DELIMITER ;
Como se ve en el procedimiento almacenado modificado anterior, agregamos un nuevo parámetro de salida llamado p_total
y seleccionó el recuento total de los deseos en función de la identificación del usuario.
También modifique el getWish
python para pasar un parámetro de salida.
_limit = pageLimit _offset = request.form['offset'] _total_records = 0 con = mysql.connect() cursor = con.cursor() cursor.callproc('sp_GetWishByUser',(_user,_limit,_offset,_total_records)) wishes = cursor.fetchall() cursor.close() cursor = con.cursor() cursor.execute('SELECT @_sp_GetWishByUser_3'); outParam = cursor.fetchall()
Como puede ver en el código anterior, una vez que llamamos al procedimiento almacenado, cerramos el cursor y abrimos un nuevo cursor para seleccionar el parámetro devuelto.
Anteriormente, devolvíamos una lista de deseos del método Python. Ahora, también debemos incluir el recuento total de registros en el JSON devuelto. Así que convertiremos el diccionario de la lista de deseos en otra lista y luego agregaremos la lista de deseos y el recuento de registros a la lista principal. Aquí está el código modificado de getWish
método Python.
response = [] wishes_dict = [] for wish in wishes: wish_dict = { 'Id': wish[0], 'Title': wish[1], 'Description': wish[2], 'Date': wish[4]} wishes_dict.append(wish_dict) response.append(wishes_dict) response.append({'total':outParam[0][0]}) return json.dumps(response)
En el GetWishes
Función de JavaScript, dentro de la devolución de llamada exitosa agregue un registro de consola.
console.log(res);
Guarde todos los cambios anteriores y reinicie el servidor. Inicie sesión con una dirección de correo electrónico y una contraseña válidas y, cuando esté en la página de inicio del usuario, consulte la consola del navegador. Debería poder ver una respuesta similar a la que se muestra a continuación:
[ [{ "Date": "Sun, 15 Feb 2015 15:10:45 GMT", "Description": "wwe", "Id": 5, "Title": "wwe" }, { "Date": "Sat, 24 Jan 2015 00:13:50 GMT", "Description": "Travel to Spain", "Id": 4, "Title": "Spain" }], { "total": 5 } ]
Usando el recuento total recibido de la respuesta, podemos obtener el número total de páginas.
var total = wishObj[1]['total']; var pageCount = total/itemsPerPage;
Dividir el recuento total de elementos de itemsPerPage
count nos da el número de páginas requeridas. Pero esto solo es cierto cuando el total es un múltiplo de itemsPerPage
. Si ese no es el caso, tendremos que comprobarlo y gestionar el recuento de páginas en consecuencia.
var pageRem = total%itemsPerPage; if(pageRem !=0 ){ pageCount = Math.floor(pageCount)+1; }
Eso nos dará el recuento de páginas correcto.
Ahora que tenemos el número total de páginas, crearemos el HTML de paginación dinámicamente. Eliminar el LI
elemento del HTML de paginación que agregamos anteriormente.
<nav> <ul class="pagination"> // li we'll create dynamically </ul> </nav>
En el GetWishes
devolución de llamada exitosa, creemos el enlace anterior dinámicamente usando jQuery.
var prevLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Previous' }) .append($('<span/>').attr('aria-hidden', 'true').html('«'))); $('.pagination').append(prevLink);
En el código anterior, acabamos de crear el enlace del botón anterior y lo agregamos a la paginación UL.
Guarde los cambios anteriores y reinicie el servidor. Al iniciar sesión correctamente, debería poder ver el enlace anterior debajo de la lista.
Del mismo modo, agreguemos las páginas en la paginación según el recuento de páginas.
for (var i = 0; i < pageCount; i++) { var page = $('<li/>').append($('<a/>').attr('href', '#').text(i + 1)); $('.pagination').append(page); }
Agreguemos también el enlace Siguiente después de que se haya agregado el enlace de las páginas.
var nextLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Next' }) .append($('<span/>').attr('aria-hidden', 'true').html('»'))); $('.pagination').append(nextLink);
Guarde los cambios y reinicie el servidor. Inicie sesión con una dirección de correo electrónico y una contraseña válidas y, una vez en la página de inicio del usuario, debería poder ver la paginación.
Adjuntar un evento de clic a un número de página
Ahora viene la lógica principal que hará que nuestra paginación sea funcional. Lo que vamos a hacer es adjuntar una llamada de evento de clic en cada índice de página para llamar a GetWishes
Función JavaScript. Primero adjuntemos un evento de clic al elemento ancla que muestra el número de página.
for (var i = 0; i < pageCount; i++) { var aPage = $('<a/>').attr('href', '#').text(i + 1); $(aPage).click(function() { }); var page = $('<li/>').append(aPage); $('.pagination').append(page); }
Así que simplemente adjuntamos un evento onclick al ancla de la página. En cada clic llamaremos al GetWishes
función y pasar el offset
. Así que declara el offset
fuera del bucle for.
var offset = 0;
Llame al GetWishes
función dentro de la llamada de evento de clic.
GetWishes(offset);
También incrementa el offset
basado en el número de registros mostrados.
offset = offset + 2;
Pero cada vez que GetWishes
se llama a la función, el valor de offset
siempre será el último conjunto. Así que haremos uso de cierres de JavaScript para pasar el desplazamiento correcto a GetWishes
función.
var offset = 0; for (var i = 0; i < pageCount; i++) { var aPage = $('<a/>').attr('href', '#').text(i + 1); $(aPage).click(function(offset) { return function() { GetWishes(offset); } }(offset)); var page = $('<li/>').append(aPage); $('.pagination').append(page); offset = offset + itemsPerPage; }
Guarde todos los cambios anteriores y reinicie el servidor. Inicie sesión con credenciales válidas y, una vez en la página de inicio del usuario, intente hacer clic en las páginas de la UL de paginación.
A continuación, implementaremos los enlaces de página anterior y siguiente. Puede parecer un poco complicado, así que déjame explicarlo un poco antes de comenzar con la implementación.
Mostraremos cinco páginas a la vez. Usando el enlace siguiente y anterior, el usuario puede navegar a las cinco páginas siguientes y cinco anteriores, respectivamente. Almacenaremos los valores de la página de inicio y la página final y seguiremos actualizando tanto en el clic del botón siguiente como en el anterior. Entonces, comencemos agregando dos campos ocultos a userHome.html
página.
<input type="hidden" id="hdnStart" value="1" /> <input type="hidden" id="hdnEnd" value="5"/>
En el GetWishes
devolución de llamada exitosa, después de haber vaciado el .pagination
UL, agregue la siguiente línea de código para obtener la página de inicio y la página final más recientes.
$('.pagination').empty(); var pageStart = $('#hdnStart').val(); var pageEnd = $('#hdnEnd').val();
No se mostrará ningún enlace de botón anterior cuando se muestren las páginas 1 a 5. Si las páginas mostradas son mayores que 5, mostraremos el enlace de botón anterior.
if (pageStart > 5) { var aPrev = $('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Previous' }) .append($('<span/>').attr('aria-hidden', 'true').html('«')); $(aPrev).click(function() { // Previous button logic }); var prevLink = $('<li/>').append(aPrev); $('.pagination').append(prevLink); }
Cuando el usuario haga clic en el botón anterior, restableceremos hdnStart
y hdnEnd
valores y llame al GetWishes
Función JavaScript.
$(aPrev).click(function() { $('#hdnStart').val(Number(pageStart) - 5); $('#hdnEnd').val(Number(pageStart) - 5 + 4); GetWishes(Number(pageStart) - 5); });
A continuación, en función de la página de inicio y la página final, crearemos un bucle y crearemos los enlaces de la página y agregaremos el .pagination
UL.
for (var i = Number(pageStart); i <= Number(pageEnd); i++) { if (i > pageCount) { break; } var aPage = $('<a/>').attr('href', '#').text(i); // Attach the page click event $(aPage).click(function(i) { return function() { GetWishes(i); } }(i)); var page = $('<li/>').append(aPage); // Attach the active page class if ((_page) == i) { $(page).attr('class', 'active'); } $('.pagination').append(page); }
Al comparar el recuento total de páginas y el valor de inicio de la página, decidiremos la visualización del enlace del siguiente botón.
if ((Number(pageStart) + 5) <= pageCount) { var nextLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Next' }) .append($('<span/>').attr('aria-hidden', 'true').html('»').click(function() { $('#hdnStart').val(Number(pageStart) + 5); $('#hdnEnd').val(Number(pageStart) + 5 + 4); GetWishes(Number(pageStart) + 5); }))); $('.pagination').append(nextLink); }
Como se ve en el código anterior, al hacer clic en el botón siguiente estamos restableciendo el hdnStart
y hdnEnd
valores de los botones y llamando a GetWishes
Función JavaScript.
Así que aquí está el GetWishes
final Función JavaScript.
function GetWishes(_page) { var _offset = (_page - 1) * 2; $.ajax({ url: '/getWish', type: 'POST', data: { offset: _offset }, success: function(res) { var itemsPerPage = 2; var wishObj = JSON.parse(res); $('#ulist').empty(); $('#listTemplate').tmpl(wishObj[0]).appendTo('#ulist'); var total = wishObj[1]['total']; var pageCount = total / itemsPerPage; var pageRem = total % itemsPerPage; if (pageRem != 0) { pageCount = Math.floor(pageCount) + 1; } $('.pagination').empty(); var pageStart = $('#hdnStart').val(); var pageEnd = $('#hdnEnd').val(); if (pageStart > 5) { var aPrev = $('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Previous' }) .append($('<span/>').attr('aria-hidden', 'true').html('«')); $(aPrev).click(function() { $('#hdnStart').val(Number(pageStart) - 5); $('#hdnEnd').val(Number(pageStart) - 5 + 4); GetWishes(Number(pageStart) - 5); }); var prevLink = $('<li/>').append(aPrev); $('.pagination').append(prevLink); } for (var i = Number(pageStart); i <= Number(pageEnd); i++) { if (i > pageCount) { break; } var aPage = $('<a/>').attr('href', '#').text(i); $(aPage).click(function(i) { return function() { GetWishes(i); } }(i)); var page = $('<li/>').append(aPage); if ((_page) == i) { $(page).attr('class', 'active'); } $('.pagination').append(page); } if ((Number(pageStart) + 5) <= pageCount) { var nextLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Next' }) .append($('<span/>').attr('aria-hidden', 'true').html('»').click(function() { $('#hdnStart').val(Number(pageStart) + 5); $('#hdnEnd').val(Number(pageStart) + 5 + 4); GetWishes(Number(pageStart) + 5); }))); $('.pagination').append(nextLink); } }, error: function(error) { console.log(error); } }); }
Guarde todos los cambios anteriores y reinicie el servidor. Inicie sesión con una dirección de correo electrónico y una contraseña válidas. Debería poder ver la paginación completamente funcional para la lista de deseos del usuario.