В предишната част на тази серия видяхме как да приложим Edit
и Delete
пожелайте функционалност за нашето приложение Bucket List. В тази част ще внедрим функционалността за пейджинг за нашия начален списък с потребители.
Първи стъпки
Нека започнем с клониране на предишната част на урока от GitHub.
git clone https://github.com/jay3dec/PythonFlaskMySQLApp_Part4.git
След като изходният код е клониран, отидете до директорията на проекта и стартирайте уеб сървъра.
cd PythonFlaskMySQLApp_Part4 python app.py
Насочете браузъра си към http://localhost:5002/ и трябва да стартирате приложението.
Внедряване на пагинация
Тъй като списъкът с желания на началната страница на потребителя се нараства, той се превърта надолу по страницата. Затова е важно да приложите пагинация. Ще ограничим броя на елементите, показани на страница до определен брой.
Променете процедурата за получаване на желание
Ще започнем с промяна на sp_GetWishByUser
процедура за връщане на резултати въз основа на limit
и offset
стойност. Този път ще създадем динамично нашия оператор за съхранена процедура, за да върнем резултатния набор въз основа на стойността на ограничението и отместването. Ето модифицирания sp_GetWishByUser
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 ;
Както се вижда в горната съхранена процедура, създадохме нашата динамична SQL заявка и я изпълнихме, за да получим списъка с желания въз основа на offset
и limit
параметри.
Добавяне на страници към потребителския интерфейс
Първо, нека дефинираме няколко настройки по подразбиране. В app.py
добавете променлива за ограничение на страниците.
# Default setting pageLimit = 2
Направете getWish
метод на python приема POST заявки.
@app.route('/getWish',methods=['POST'])
Прочетете offset
и limit
вътре в getWish
метод и го предайте, докато извиквате съхранената процедура на 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()
Променете GetWishes
JavaScript функция в userHome.html
за да го направите POST заявка и да предадете offset
стойност.
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); } }); }
Запазете всички промени и рестартирайте сървъра. Влезте с валиден имейл адрес и парола и трябва да имате само два записа, показани на екрана.
Така че частта от базата данни работи добре. След това трябва да добавим потребителския интерфейс за пагинация към началната страница на потребителя, което ще позволи на потребителя да се движи в данните.
Ще използваме компонента за пагинация на Bootstrap. Отворете userHome.html
и добавете следния HTML код след #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>
Запазете промените и рестартирайте сървъра. След успешното влизане, трябва да можете да видите пагинацията под списъка с желания.
Направяне на пагинация динамична
Горната пагинация е как ще изглежда нашата пагинация. Но за да го направим функционален, трябва да създадем динамично нашата пагинация въз основа на броя на записите в базата данни.
За да създадем нашата пагинация, ще ни трябва общият брой записи, налични в базата данни. Така че нека променим съхранената процедура на MySQL sp_GetWishByUser
за да върне общия брой записи, налични като изходящ параметър.
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 ;
Както се вижда в горната модифицирана съхранена процедура, добавихме нов изходен параметър, наречен p_total
и избра общия брой на желанията въз основа на потребителския идентификатор.
Променете също getWish
python метод за предаване на изходен параметър.
_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()
Както можете да видите в горния код, след като извикаме съхранената процедура, затваряме курсора и отваряме нов курсор, за да изберем върнатия параметър.
По-рано връщахме списък с желания от метода Python. Сега също трябва да включим общия брой записи в върнатия JSON. Така че ще направим речника на списъка с желания в друг списък и след това ще добавим списъка с желания и броя на записите към основния списък. Ето модифицирания код на getWish
метод на 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)
В GetWishes
JavaScript функция, вътре в успешното обратно извикване добавете конзолен журнал.
console.log(res);
Запазете всички горни промени и рестартирайте сървъра. Влезте с валиден имейл адрес и парола и когато сте на началната страница на потребителя, проверете конзолата на браузъра. Трябва да можете да видите отговор, подобен на показания по-долу:
[ [{ "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 } ]
Използвайки общия брой, получен от отговора, можем да получим общия брой страници.
var total = wishObj[1]['total']; var pageCount = total/itemsPerPage;
Разделяне на общия брой елементи от itemsPerPage
count ни дава необходимия брой страници. Но това важи само когато общата сума е кратна на itemsPerPage
. Ако това не е така, ще трябва да проверим за това и съответно да обработваме броя на страниците.
var pageRem = total%itemsPerPage; if(pageRem !=0 ){ pageCount = Math.floor(pageCount)+1; }
Така че това ще ни даде правилния брой страници.
Сега, тъй като разполагаме с общия брой страници, ще създадем динамично HTML за пагинация. Премахнете LI
елемент от HTML за пагинация, който добавихме по-рано.
<nav> <ul class="pagination"> // li we'll create dynamically </ul> </nav>
В GetWishes
успешно обратно извикване, нека създадем предишната връзка динамично с помощта на jQuery.
var prevLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Previous' }) .append($('<span/>').attr('aria-hidden', 'true').html('«'))); $('.pagination').append(prevLink);
В кода по-горе току-що създадохме предишната връзка с бутон и я добавихме към UL пагинация.
Запазете горните промени и рестартирайте сървъра. При успешно влизане трябва да можете да видите предишната връзка под списъка.
По същия начин, нека добавим страниците в пагинацията въз основа на броя на страниците.
for (var i = 0; i < pageCount; i++) { var page = $('<li/>').append($('<a/>').attr('href', '#').text(i + 1)); $('.pagination').append(page); }
Нека добавим и връзката Следваща, след като връзката към страниците бъде добавена.
var nextLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Next' }) .append($('<span/>').attr('aria-hidden', 'true').html('»'))); $('.pagination').append(nextLink);
Запазете промените и рестартирайте сървъра. Влезте с валиден имейл адрес и парола и веднъж на началната страница на потребителя трябва да можете да видите пагинацията.
Прикачване на събитие за щракване към номер на страница
Сега идва основната логика, която ще направи пагинацията ни функционална. Това, което ще направим, е да прикачим извикване на събитие за кликване към всеки индекс на страница, за да извикаме GetWishes
JavaScript функция. Нека първо прикачим събитие за щракване към елемента за закотвяне, показващ номера на страницата.
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); }
Така че току-що прикачихме събитие onclick към котвата на страницата. При всяко щракване ще извикаме GetWishes
функция и предайте offset
. Така че декларирайте offset
извън цикъла for.
var offset = 0;
Обадете се на GetWishes
функция в извикването на събитие за щракване.
GetWishes(offset);
Също така увеличете offset
въз основа на броя на показаните записи.
offset = offset + 2;
Но всеки път GetWishes
функцията се извиква, стойността на offset
винаги ще бъде последният набор. Така че ще използваме JavaScript Closures, за да предадем правилното изместване към GetWishes
функция.
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; }
Запазете всички горни промени и рестартирайте сървъра. Влезте с валидни идентификационни данни и веднъж на началната страница на потребителя, опитайте да щракнете върху страниците в UL за пагинация.
След това ще приложим връзките към предишната и следващата страница. Може да изглежда малко сложно, така че позволете ми да го обясня малко, преди да започнем с внедряването.
Ще показваме пет страници наведнъж. Използвайки следващата и предишната връзка, потребителят може да навигира съответно до следващите пет и предходните пет страници. Ще съхраняваме стойностите на началната и крайната страница и ще продължим да актуализираме както при следващото, така и при предишното щракване върху бутон. Така че нека започнем с добавяне на две скрити полета към userHome.html
страница.
<input type="hidden" id="hdnStart" value="1" /> <input type="hidden" id="hdnEnd" value="5"/>
В GetWishes
успешно обратно извикване, след като сме изпразнили .pagination
UL, добавете следния ред код, за да получите най-новата начална и крайна страница.
$('.pagination').empty(); var pageStart = $('#hdnStart').val(); var pageEnd = $('#hdnEnd').val();
Няма да се показва връзка към предишния бутон, когато се показват страници от 1 до 5. Ако показаните страници са по-големи от 5, тогава ще покажем връзката към предишния бутон.
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); }
Когато потребителят щракне върху предишния бутон, ще нулираме hdnStart
и hdnEnd
стойности и извикайте GetWishes
JavaScript функция.
$(aPrev).click(function() { $('#hdnStart').val(Number(pageStart) - 5); $('#hdnEnd').val(Number(pageStart) - 5 + 4); GetWishes(Number(pageStart) - 5); });
След това, въз основа на началната и крайната страница, ще завъртим и ще създадем връзките към страницата и ще добавим .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); }
Сравнявайки общия брой страници и началната стойност на страницата, ще решим как да се покаже връзката към следващия бутон.
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); }
Както се вижда в горния код, при следващото щракване върху бутон ние нулираме hdnStart
и hdnEnd
стойности на бутоните и извикване на GetWishes
JavaScript функция.
И така, ето последният GetWishes
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); } }); }
Запазете всички горни промени и рестартирайте сървъра. Влезте с валиден имейл адрес и парола. Трябва да можете да видите напълно функционалната пагинация за потребителския списък с желания.