W poprzedniej części tej serii widzieliśmy, jak zaimplementować Edit
i Delete
funkcja życzeń dla naszej aplikacji Bucket List. W tej części zaimplementujemy funkcjonalność stronicowania dla naszej listy domowej użytkowników.
Pierwsze kroki
Zacznijmy od sklonowania poprzedniej części samouczka z GitHub.
git clone https://github.com/jay3dec/PythonFlaskMySQLApp_Part4.git
Po sklonowaniu kodu źródłowego przejdź do katalogu projektu i uruchom serwer WWW.
cd PythonFlaskMySQLApp_Part4 python app.py
Skieruj przeglądarkę na http://localhost:5002/ i powinieneś mieć uruchomioną aplikację.
Implementacja stronicowania
W miarę powiększania się listy życzeń na stronie głównej użytkownika jest ona przewijana w dół strony. Dlatego ważne jest, aby wdrożyć paginację. Ograniczymy liczbę elementów wyświetlanych na stronie do określonej liczby.
Zmień procedurę pobierania życzeń
Zaczniemy od zmodyfikowania sp_GetWishByUser
procedura zwracania wyników w oparciu o limit
i offset
wartość. Tym razem będziemy tworzyć naszą instrukcję procedury składowanej dynamicznie, aby zwrócić zestaw wyników na podstawie wartości limitu i przesunięcia. Oto zmodyfikowany sp_GetWishByUser
Procedura składowana 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 ;
Jak widać w powyższej procedurze składowanej, stworzyliśmy nasze dynamiczne zapytanie SQL i wykonaliśmy je, aby uzyskać listę życzeń opartą na offset
i limit
parametry.
Dodawanie stronicowania do interfejsu
Najpierw zdefiniujmy kilka domyślnych ustawień. W app.py
dodaj zmienną dla limitu stron.
# Default setting pageLimit = 2
Zrób getWish
Metoda Pythona akceptuje żądania POST.
@app.route('/getWish',methods=['POST'])
Przeczytaj offset
i limit
wewnątrz getWish
i przekazać ją podczas wywoływania procedury składowanej 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()
Zmodyfikuj GetWishes
Funkcja JavaScript w userHome.html
aby uczynić to żądaniem POST i przekazać offset
wartość.
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); } }); }
Zapisz wszystkie zmiany i uruchom ponownie serwer. Zaloguj się przy użyciu prawidłowego adresu e-mail i hasła, a na ekranie powinny być wyświetlane tylko dwa rekordy.
Więc część bazy danych działa dobrze. Następnie musimy dodać interfejs stronicowania do strony głównej użytkownika, co umożliwi użytkownikowi nawigację po danych.
Wykorzystamy składnik stronicowania Bootstrap. Otwórz userHome.html
i dodaj następujący kod HTML po #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>
Zapisz zmiany i uruchom ponownie serwer. Po pomyślnym zalogowaniu powinieneś być w stanie zobaczyć paginację pod listą życzeń.
Dynamiczne tworzenie stronicowania
Powyższa paginacja jest tym, jak będzie wyglądać nasza paginacja. Ale aby było funkcjonalne, musimy tworzyć naszą paginację dynamicznie w oparciu o liczbę rekordów w bazie danych.
Aby stworzyć naszą paginację, będziemy potrzebować całkowitej liczby rekordów dostępnych w bazie danych. Zmodyfikujmy więc procedurę składowaną MySQL sp_GetWishByUser
aby zwrócić całkowitą liczbę rekordów dostępnych jako parametr out.
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 ;
Jak widać w powyższej zmodyfikowanej procedurze składowanej, dodaliśmy nowy parametr wyjściowy o nazwie p_total
i wybrał całkowitą liczbę życzeń na podstawie identyfikatora użytkownika.
Zmodyfikuj także getWish
metoda Pythona do przekazania parametru wyjściowego.
_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()
Jak widać w powyższym kodzie, po wywołaniu procedury składowanej zamykamy kursor i otwieramy nowy kursor, aby wybrać zwrócony parametr out.
Wcześniej zwracaliśmy listę życzeń z metody Pythona. Teraz musimy również uwzględnić całkowitą liczbę rekordów w zwróconym pliku JSON. Utworzymy więc słownik listy życzeń w innej liście, a następnie dodamy listę życzeń i liczbę rekordów do głównej listy. Oto zmodyfikowany kod getWish
metoda Pythona.
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)
W GetWishes
Funkcja JavaScript, wewnątrz wywołania zwrotnego sukcesu dodaj dziennik konsoli.
console.log(res);
Zapisz wszystkie powyższe zmiany i uruchom ponownie serwer. Zaloguj się przy użyciu prawidłowego adresu e-mail i hasła, a na stronie głównej użytkownika sprawdź konsolę przeglądarki. Powinna być widoczna odpowiedź podobna do tej pokazanej poniżej:
[ [{ "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 } ]
Korzystając z łącznej liczby otrzymanej z odpowiedzi, możemy uzyskać całkowitą liczbę stron.
var total = wishObj[1]['total']; var pageCount = total/itemsPerPage;
Dzielenie całkowitej liczby elementów z itemsPerPage
count podaje nam wymaganą liczbę stron. Ale obowiązuje to tylko wtedy, gdy suma jest wielokrotnością itemsPerPage
. Jeśli tak nie jest, będziemy musieli to sprawdzić i odpowiednio obsłużyć liczbę stron.
var pageRem = total%itemsPerPage; if(pageRem !=0 ){ pageCount = Math.floor(pageCount)+1; }
Dzięki temu uzyskamy prawidłową liczbę stron.
Teraz, ponieważ mamy całkowitą liczbę stron, dynamicznie utworzymy kod HTML paginacji. Usuń LI
element z kodu HTML stronicowania, który dodaliśmy wcześniej.
<nav> <ul class="pagination"> // li we'll create dynamically </ul> </nav>
W GetWishes
powodzenia wywołania zwrotnego, stwórzmy poprzedni link dynamicznie za pomocą jQuery.
var prevLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Previous' }) .append($('<span/>').attr('aria-hidden', 'true').html('«'))); $('.pagination').append(prevLink);
W powyższym kodzie właśnie utworzyliśmy poprzedni link do przycisku i dołączyliśmy go do strony UL.
Zapisz powyższe zmiany i uruchom ponownie serwer. Po pomyślnym zalogowaniu powinieneś być w stanie zobaczyć poprzedni link pod listą.
Podobnie dodajmy strony w paginacji na podstawie liczby stron.
for (var i = 0; i < pageCount; i++) { var page = $('<li/>').append($('<a/>').attr('href', '#').text(i + 1)); $('.pagination').append(page); }
Dodajmy również link Dalej po dodaniu linku do stron.
var nextLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Next' }) .append($('<span/>').attr('aria-hidden', 'true').html('»'))); $('.pagination').append(nextLink);
Zapisz zmiany i uruchom ponownie serwer. Zaloguj się przy użyciu prawidłowego adresu e-mail i hasła, a po wejściu na stronę główną użytkownika powinieneś zobaczyć podział na strony.
Dołączanie zdarzenia kliknięcia do numeru strony
Teraz pojawia się główna logika, która sprawi, że nasza paginacja będzie funkcjonalna. Zamierzamy dołączyć wywołanie zdarzenia kliknięcia do każdego indeksu strony, aby wywołać funkcję GetWishes
Funkcja JavaScript. Najpierw dołączmy zdarzenie kliknięcia do elementu zakotwiczenia wyświetlającego numer strony.
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); }
Dlatego właśnie dołączyliśmy zdarzenie onclick do kotwicy strony. Przy każdym kliknięciu wywołamy GetWishes
funkcji i przekaż offset
. Więc zadeklaruj offset
poza pętlą for.
var offset = 0;
Zadzwoń do GetWishes
funkcja wewnątrz wywołania zdarzenia kliknięcia.
GetWishes(offset);
Zwiększ także offset
na podstawie liczby pokazanych rekordów.
offset = offset + 2;
Ale za każdym razem GetWishes
wywoływana jest funkcja, wartość offset
zawsze będzie ostatnim zestawem. Dlatego użyjemy zamknięć JavaScript, aby przekazać poprawne przesunięcie do GetWishes
funkcja.
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; }
Zapisz wszystkie powyższe zmiany i uruchom ponownie serwer. Zaloguj się przy użyciu prawidłowych danych logowania, a na stronie głównej użytkownika spróbuj kliknąć strony w UL paginacji.
Następnie zaimplementujemy linki do poprzedniej i następnej strony. Może się to wydawać nieco skomplikowane, więc wyjaśnię to trochę zanim przystąpimy do wdrożenia.
Jednocześnie będziemy wyświetlać pięć stron. Korzystając z następnego i poprzedniego łącza, użytkownik może przejść odpowiednio do następnych pięciu i poprzednich pięciu stron. Będziemy przechowywać wartości strony początkowej i końcowej oraz aktualizować zarówno przy następnym, jak i poprzednim kliknięciu przycisku. Zacznijmy więc od dodania dwóch ukrytych pól do userHome.html
strona.
<input type="hidden" id="hdnStart" value="1" /> <input type="hidden" id="hdnEnd" value="5"/>
W GetWishes
powodzenia wywołania zwrotnego, po opróżnieniu .pagination
UL, dodaj następujący wiersz kodu, aby uzyskać najnowszą stronę początkową i końcową.
$('.pagination').empty(); var pageStart = $('#hdnStart').val(); var pageEnd = $('#hdnEnd').val();
Żaden link do poprzedniego przycisku nie zostanie wyświetlony podczas wyświetlania stron od 1 do 5. Jeśli liczba wyświetlanych stron jest większa niż 5, wyświetlimy link do poprzedniego przycisku.
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); }
Gdy użytkownik kliknie poprzedni przycisk, zresetujemy hdnStart
i hdnEnd
wartości i wywołaj GetWishes
Funkcja JavaScript.
$(aPrev).click(function() { $('#hdnStart').val(Number(pageStart) - 5); $('#hdnEnd').val(Number(pageStart) - 5 + 4); GetWishes(Number(pageStart) - 5); });
Następnie, w oparciu o stronę początkową i końcową, zapętlimy i utworzymy linki do stron oraz dołączymy .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); }
Porównując całkowitą liczbę stron i wartość początkową strony, zdecydujemy o wyświetlaniu następnego linku przycisku.
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); }
Jak widać w powyższym kodzie, przy następnym kliknięciu przycisku resetujemy hdnStart
i hdnEnd
wartości przycisków i wywołanie funkcji GetWishes
Funkcja JavaScript.
Oto ostatnie GetWishes
Funkcja 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); } }); }
Zapisz wszystkie powyższe zmiany i uruchom ponownie serwer. Zaloguj się przy użyciu prawidłowego adresu e-mail i hasła. Powinieneś być w stanie zobaczyć w pełni funkcjonalną paginację listy życzeń użytkownika.