Trong phần trước của loạt bài này, chúng ta đã biết cách triển khai Edit
và Delete
chức năng mong muốn cho Ứng dụng Danh sách Nhóm của chúng tôi. Trong phần này, chúng tôi sẽ triển khai chức năng phân trang cho danh sách trang chủ người dùng của chúng tôi.
Bắt đầu
Hãy bắt đầu bằng cách sao chép phần trước của hướng dẫn từ GitHub.
git clone https://github.com/jay3dec/PythonFlaskMySQLApp_Part4.git
Khi mã nguồn đã được nhân bản, hãy điều hướng đến thư mục dự án và khởi động máy chủ web.
cd PythonFlaskMySQLApp_Part4 python app.py
Trỏ trình duyệt của bạn đến http:// localhost:5002 / và bạn sẽ có ứng dụng đang chạy.
Triển khai phân trang
Khi danh sách mong muốn trên trang chủ của người dùng tăng lên, nó sẽ được cuộn xuống trang. Vì vậy, điều quan trọng là phải triển khai phân trang. Chúng tôi sẽ giới hạn số lượng mục hiển thị trên một trang ở một số lượng nhất định.
Sửa đổi Thủ tục Nhận Điều ước
Chúng tôi sẽ bắt đầu bằng cách sửa đổi sp_GetWishByUser
quy trình trả về kết quả dựa trên limit
và offset
giá trị. Lần này, chúng tôi sẽ tạo động câu lệnh thủ tục được lưu trữ của chúng tôi để trả về tập kết quả dựa trên giá trị giới hạn và giá trị bù đắp. Đây là sp_GetWishByUser
đã sửa đổi Thủ tục lưu trữ 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 ;
Như đã thấy trong quy trình được lưu trữ ở trên, chúng tôi đã tạo truy vấn SQL động của mình và thực thi nó để có được danh sách mong muốn dựa trên offset
và limit
tham số.
Thêm phân trang vào giao diện người dùng
Đầu tiên, hãy xác định một vài cài đặt mặc định. Trong app.py
thêm một biến cho giới hạn trang.
# Default setting pageLimit = 2
Tạo getWish
phương thức python chấp nhận yêu cầu POST.
@app.route('/getWish',methods=['POST'])
Đọc offset
và limit
bên trong getWish
và chuyển nó trong khi gọi thủ tục được lưu trữ 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()
Sửa đổi GetWishes
Hàm JavaScript trong userHome.html
để biến nó thành một yêu cầu ĐĂNG và chuyển offset
giá trị.
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); } }); }
Lưu tất cả các thay đổi và khởi động lại máy chủ. Đăng nhập bằng địa chỉ email và mật khẩu hợp lệ và bạn sẽ chỉ có hai bản ghi được hiển thị trên màn hình.
Vì vậy, phần cơ sở dữ liệu đang hoạt động tốt. Tiếp theo, chúng ta cần thêm giao diện người dùng phân trang vào trang chủ của người dùng, điều này sẽ cho phép người dùng điều hướng trên dữ liệu.
Chúng tôi sẽ sử dụng thành phần phân trang Bootstrap. Mở userHome.html
và thêm mã HTML sau vào sau #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>
Lưu các thay đổi và khởi động lại máy chủ. Sau khi đăng nhập thành công, bạn sẽ có thể thấy phân trang trong danh sách mong muốn.
Làm cho phân trang động
Sự phân trang ở trên là cách phân trang của chúng ta sẽ trông như thế nào. Nhưng để làm cho nó hoạt động, chúng ta cần tạo phân trang động dựa trên số lượng bản ghi trong cơ sở dữ liệu.
Để tạo phân trang của chúng tôi, chúng tôi sẽ cần tổng số bản ghi có sẵn trong cơ sở dữ liệu. Vì vậy, hãy sửa đổi thủ tục lưu trữ MySQL sp_GetWishByUser
để trả về tổng số bản ghi có sẵn dưới dạng tham số 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 ;
Như đã thấy trong quy trình được lưu trữ đã sửa đổi ở trên, chúng tôi đã thêm một tham số đầu ra mới có tên là p_total
và chọn tổng số mong muốn dựa trên id người dùng.
Đồng thời sửa đổi getWish
phương thức python để chuyển một tham số đầu ra.
_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()
Như bạn có thể thấy trong đoạn mã trên, khi chúng ta đã gọi thủ tục được lưu trữ, chúng ta đóng con trỏ và mở một con trỏ mới để chọn tham số trả về.
Trước đó, chúng tôi đã trả về một danh sách các điều ước từ phương thức Python. Bây giờ, chúng ta cũng cần bao gồm tổng số bản ghi trong JSON được trả về. Vì vậy, chúng tôi sẽ tạo từ điển danh sách mong muốn thành một danh sách khác và sau đó thêm danh sách mong muốn và số bản ghi vào danh sách chính. Đây là mã đã sửa đổi của getWish
phương pháp 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)
Trong GetWishes
Hàm JavaScript, bên trong lệnh gọi lại thành công, hãy thêm nhật ký bảng điều khiển.
console.log(res);
Lưu tất cả các thay đổi trên và khởi động lại máy chủ. Đăng nhập bằng địa chỉ email và mật khẩu hợp lệ và khi ở trên trang chủ của người dùng, hãy kiểm tra bảng điều khiển của trình duyệt. Bạn sẽ có thể thấy phản hồi tương tự như phản hồi được hiển thị bên dưới:
[ [{ "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 } ]
Sử dụng tổng số nhận được từ phản hồi, chúng tôi có thể nhận được tổng số trang.
var total = wishObj[1]['total']; var pageCount = total/itemsPerPage;
Chia tổng số mục cho itemsPerPage
số lượng cung cấp cho chúng tôi số lượng trang được yêu cầu. Nhưng điều này chỉ đúng khi tổng là bội số của itemsPerPage
. Nếu không đúng như vậy, chúng tôi sẽ phải kiểm tra điều đó và xử lý số lượng trang cho phù hợp.
var pageRem = total%itemsPerPage; if(pageRem !=0 ){ pageCount = Math.floor(pageCount)+1; }
Vì vậy, điều đó sẽ cung cấp cho chúng tôi số lượng trang chính xác.
Bây giờ vì chúng tôi có tổng số trang, chúng tôi sẽ tạo HTML phân trang động. Xóa LI
phần tử từ HTML phân trang mà chúng tôi đã thêm trước đó.
<nav> <ul class="pagination"> // li we'll create dynamically </ul> </nav>
Trong GetWishes
gọi lại thành công, hãy tạo động liên kết trước đó bằng jQuery.
var prevLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Previous' }) .append($('<span/>').attr('aria-hidden', 'true').html('«'))); $('.pagination').append(prevLink);
Trong đoạn mã trên, chúng tôi vừa tạo liên kết nút trước đó và nối nó vào UL phân trang.
Lưu các thay đổi trên và khởi động lại máy chủ. Khi đăng nhập thành công, bạn sẽ có thể thấy liên kết trước đó trong danh sách.
Tương tự, hãy thêm các trang trong phân trang dựa trên số lượng trang.
for (var i = 0; i < pageCount; i++) { var page = $('<li/>').append($('<a/>').attr('href', '#').text(i + 1)); $('.pagination').append(page); }
Cũng hãy thêm liên kết Tiếp theo sau khi liên kết trang đã được thêm.
var nextLink = $('<li/>').append($('<a/>').attr({ 'href': '#' }, { 'aria-label': 'Next' }) .append($('<span/>').attr('aria-hidden', 'true').html('»'))); $('.pagination').append(nextLink);
Lưu các thay đổi và khởi động lại máy chủ. Đăng nhập bằng địa chỉ email và mật khẩu hợp lệ và khi ở trên trang chủ của người dùng, bạn sẽ có thể xem phân trang.
Đính kèm sự kiện nhấp chuột vào số trang
Bây giờ là logic chính sẽ làm cho việc phân trang của chúng ta hoạt động. Những gì chúng ta sẽ làm là đính kèm một lệnh gọi sự kiện nhấp chuột trên mỗi chỉ mục trang để gọi GetWishes
Hàm JavaScript. Trước tiên, hãy đính kèm một sự kiện nhấp chuột vào phần tử liên kết hiển thị số trang.
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); }
Vì vậy, chúng tôi vừa đính kèm một sự kiện onclick vào liên kết trang. Trên mỗi lần nhấp, chúng tôi sẽ gọi GetWishes
hàm và chuyển offset
. Vì vậy, khai báo offset
bên ngoài vòng lặp for.
var offset = 0;
Gọi cho GetWishes
chức năng bên trong lệnh gọi sự kiện nhấp chuột.
GetWishes(offset);
Đồng thời tăng offset
dựa trên số lượng bản ghi được hiển thị.
offset = offset + 2;
Nhưng mỗi lần GetWishes
hàm được gọi, giá trị của offset
sẽ luôn là bộ cuối cùng. Vì vậy, chúng tôi sẽ sử dụng JavaScript Closures để chuyển phần bù chính xác cho GetWishes
chức năng.
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; }
Lưu tất cả các thay đổi trên và khởi động lại máy chủ. Đăng nhập bằng thông tin xác thực hợp lệ và khi ở trên trang chủ của người dùng, hãy thử nhấp vào các trang trong UL phân trang.
Tiếp theo, chúng tôi sẽ triển khai các liên kết trang trước và trang tiếp theo. Nó có vẻ hơi phức tạp, vì vậy hãy để tôi giải thích một chút trước khi chúng ta bắt đầu thực hiện.
Chúng tôi sẽ hiển thị năm trang cùng một lúc. Sử dụng liên kết tiếp theo và trước đó, người dùng có thể điều hướng đến năm trang tiếp theo và năm trang trước tương ứng. Chúng tôi sẽ lưu trữ các giá trị của trang bắt đầu và trang kết thúc và tiếp tục cập nhật cả khi nhấp vào nút tiếp theo và trước đó. Vì vậy, hãy bắt đầu bằng cách thêm hai trường ẩn vào userHome.html
trang.
<input type="hidden" id="hdnStart" value="1" /> <input type="hidden" id="hdnEnd" value="5"/>
Trong GetWishes
gọi lại thành công, sau khi chúng tôi đã làm trống .pagination
UL, thêm dòng mã sau để có trang bắt đầu và trang kết thúc mới nhất.
$('.pagination').empty(); var pageStart = $('#hdnStart').val(); var pageEnd = $('#hdnEnd').val();
Không có liên kết nút nào trước đó sẽ được hiển thị khi hiển thị các trang từ 1 đến 5. Nếu các trang được hiển thị lớn hơn 5 thì chúng tôi sẽ hiển thị liên kết nút trước đó.
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); }
Khi người dùng nhấp vào nút trước đó, chúng tôi sẽ đặt lại hdnStart
và hdnEnd
và gọi GetWishes
Hàm JavaScript.
$(aPrev).click(function() { $('#hdnStart').val(Number(pageStart) - 5); $('#hdnEnd').val(Number(pageStart) - 5 + 4); GetWishes(Number(pageStart) - 5); });
Tiếp theo, dựa trên trang bắt đầu và trang kết thúc, chúng tôi sẽ lặp lại và tạo các liên kết trang và nối .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); }
Bằng cách so sánh tổng số trang và giá trị bắt đầu của trang, chúng tôi sẽ quyết định việc hiển thị liên kết nút tiếp theo.
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); }
Như đã thấy trong đoạn mã trên, khi nhấp vào nút tiếp theo, chúng tôi đang đặt lại hdnStart
và hdnEnd
giá trị nút và gọi GetWishes
Hàm JavaScript.
Vì vậy, đây là GetWishes
cuối cùng Hàm 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); } }); }
Lưu tất cả các thay đổi trên và khởi động lại máy chủ. Đăng nhập bằng địa chỉ email và mật khẩu hợp lệ. Bạn sẽ có thể thấy phân trang đầy đủ chức năng cho danh sách mong muốn của người dùng.