Статьи

Создание веб-приложения с нуля с использованием Python Flask и MySQL: часть 5

В предыдущей части этой серии мы увидели, как реализовать функциональность « Edit и Delete пожелания» для нашего приложения списка корзин. В этой части мы реализуем функцию подкачки для нашего домашнего списка пользователей.

Давайте начнем с клонирования предыдущей части руководства от GitHub .

1
git clone https://github.com/jay3dec/PythonFlaskMySQLApp_Part4.git

После того, как исходный код был клонирован, перейдите в каталог проекта и запустите веб-сервер.

1
2
cd PythonFlaskMySQLApp_Part4
python app.py

Укажите в браузере http: // localhost: 5002 /, и приложение должно быть запущено.

Когда список желаний на домашней странице пользователя увеличивается, он прокручивается вниз по странице. Поэтому важно реализовать нумерацию страниц. Мы будем ограничивать количество элементов, отображаемых на странице, определенным числом.

Мы начнем с изменения процедуры sp_GetWishByUser , чтобы она возвращала результаты на основе значения limit и offset . На этот раз мы будем динамически создавать оператор хранимой процедуры, чтобы он возвращал набор результатов на основе значений предела и смещения. Вот модифицированная хранимая процедура MySQL sp_GetWishByUser .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
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 добавьте переменную для ограничения страницы.

1
2
# Default setting
pageLimit = 2

Заставьте getWish Python getWish принимать запросы POST.

1
@app.route(‘/getWish’,methods=[‘POST’])

Считайте offset и limit внутри метода getWish и передайте его при вызове хранимой процедуры MySQL sp_GetWishByUser .

1
2
3
4
5
6
7
8
_limit = pageLimit
 _offset = request.form[‘offset’]
 
 
con = mysql.connect()
cursor = con.cursor()
cursor.callproc(‘sp_GetWishByUser’,(_user,_limit,_offset))
wishes = cursor.fetchall()

Измените GetWishes JavaScript GetWishes в userHome.html чтобы сделать ее запросом POST и передать значение offset .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
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.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<nav>
    <ul class=»pagination»>
        <li>
            <a href=»#» aria-label=»Previous»>
                <span aria-hidden=»true»>&laquo;
            </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»>&raquo;
            </a>
        </li>
    </ul>
</nav>

Сохраните изменения и перезапустите сервер. После успешного входа в систему вы сможете увидеть нумерацию страниц под списком пожеланий.

Нумерация страниц на домашней странице пользователя

Вышеупомянутая нумерация страниц — то, как будет выглядеть наша нумерация страниц. Но чтобы сделать его функциональным, нам нужно динамически создавать нумерацию страниц в зависимости от количества записей в базе данных.

Чтобы создать нашу нумерацию страниц, нам понадобится общее количество записей, доступных в базе данных. Итак, давайте sp_GetWishByUser хранимую процедуру MySQL sp_GetWishByUser чтобы она возвращала общее количество записей, доступных в качестве параметра out.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
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 getWish для передачи выходного параметра.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
_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()

Как видно из приведенного выше кода, после вызова хранимой процедуры мы закрываем курсор и открываем новый курсор, чтобы выбрать возвращаемый параметр out.

Ранее мы возвращали список пожеланий из метода Python. Теперь нам также нужно включить общее количество записей в возвращенный JSON. Итак, мы превратим словарь списка желаний в другой список, а затем добавим список желаний и количество записей в основной список. Вот модифицированный код getWish Python getWish .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
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 GetWishes внутри обратного вызова успешно добавьте консольный журнал.

1
console.log(res);

Сохраните все вышеперечисленные изменения и перезагрузите сервер. Войдите в систему, используя действующий адрес электронной почты и пароль, и на домашней странице пользователя проверьте консоль браузера. Вы должны увидеть ответ, подобный показанному ниже:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
[
    [{
        «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
    }
]

Используя общее количество полученных из ответа, мы можем получить общее количество страниц.

1
2
var total = wishObj[1][‘total’];
var pageCount = total/itemsPerPage;

Разделив общее количество элементов от itemsPerPage мы получим необходимое количество страниц. Но это справедливо только в том случае, если сумма кратна itemsPerPage . Если это не так, мы должны это проверить и соответствующим образом обработать количество страниц.

1
2
3
4
var pageRem = total%itemsPerPage;
if(pageRem !=0 ){
    pageCount = Math.floor(pageCount)+1;
}

Так что это даст нам правильное количество страниц.

Теперь, когда у нас есть общее количество страниц, мы будем динамически создавать HTML-нумерацию страниц. Удалите элемент LI из HTML-страниц, которые мы добавили ранее.

1
2
3
4
5
<nav>
    <ul class=»pagination»>
        // li we’ll create dynamically
    </ul>
</nav>

В GetWishes успеха GetWishes давайте создадим предыдущую ссылку динамически, используя jQuery .

1
2
3
4
5
6
7
8
var prevLink = $(‘<li/>’).append($(‘<a/>’).attr({
        ‘href’: ‘#’
    }, {
        ‘aria-label’: ‘Previous’
    })
    .append($(‘<span/>’).attr(‘aria-hidden’, ‘true’).html(‘&laquo;’)));
 
$(‘.pagination’).append(prevLink);

В приведенном выше коде мы только что создали ссылку на предыдущую кнопку и добавили ее к нумерации страниц.

Сохраните вышеуказанные изменения и перезагрузите сервер. При успешном входе в систему вы должны увидеть предыдущую ссылку под списком.

Предыдущая ссылка в пагинации

Аналогично, давайте добавим страницы в разбивке по страницам на основе количества страниц.

1
2
3
4
for (var i = 0; i < pageCount; i++) {
    var page = $(‘<li/>’).append($(‘<a/>’).attr(‘href’, ‘#’).text(i + 1));
    $(‘.pagination’).append(page);
}

Давайте также добавим ссылку «Далее» после добавления ссылки на страницы.

1
2
3
4
5
6
7
8
var nextLink = $(‘<li/>’).append($(‘<a/>’).attr({
        ‘href’: ‘#’
    }, {
        ‘aria-label’: ‘Next’
    })
    .append($(‘<span/>’).attr(‘aria-hidden’, ‘true’).html(‘&raquo;’)));
 
$(‘.pagination’).append(nextLink);

Сохраните изменения и перезапустите сервер. Войдите, используя действующий адрес электронной почты и пароль, и однажды на домашней странице пользователя вы сможете увидеть нумерацию страниц.

Нумерация страниц на домашней странице пользователя

Теперь приходит основная логика, которая сделает нашу функциональную нумерацию страниц. Что мы собираемся сделать, это прикрепить вызов события click к каждому индексу страницы, чтобы вызвать GetWishes JavaScript GetWishes . Давайте сначала прикрепим событие click к элементу привязки, отображающему номер страницы.

01
02
03
04
05
06
07
08
09
10
11
12
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.

1
var offset = 0;

Вызовите функцию GetWishes внутри вызова события click.

1
GetWishes(offset);

Также увеличьте offset зависимости от количества отображаемых записей.

1
offset = offset + 2;

Но каждый раз, когда GetWishes функция GetWishes , значение offset всегда будет последним установленным. Поэтому мы будем использовать JavaScript-замыкания для передачи правильного смещения в функцию GetWishes .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
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 .

1
2
<input type=»hidden» id=»hdnStart» value=»1″ />
<input type=»hidden» id=»hdnEnd» value=»5″/>

GetWishes успешного GetWishes обратного вызова .pagination в .pagination добавьте следующую строку кода, чтобы получить последнюю начальную и конечную страницы.

1
2
3
4
$(‘.pagination’).empty();
 
var pageStart = $(‘#hdnStart’).val();
var pageEnd = $(‘#hdnEnd’).val();

Предыдущая ссылка на кнопку не будет отображаться при отображении страниц с 1 по 5. Если отображаемых страниц больше 5, мы отобразим предыдущую ссылку на кнопку.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
if (pageStart > 5) {
    var aPrev = $(‘<a/>’).attr({
            ‘href’: ‘#’
        }, {
            ‘aria-label’: ‘Previous’
        })
        .append($(‘<span/>’).attr(‘aria-hidden’, ‘true’).html(‘&laquo;’));
 
    $(aPrev).click(function() {
        // Previous button logic
    });
 
    var prevLink = $(‘<li/>’).append(aPrev);
    $(‘.pagination’).append(prevLink);
}

Когда пользователь нажимает предыдущую кнопку, мы сбрасываем значения hdnStart и hdnEnd и GetWishes функцию GetWishes JavaScript.

1
2
3
4
5
$(aPrev).click(function() {
    $(‘#hdnStart’).val(Number(pageStart) — 5);
    $(‘#hdnEnd’).val(Number(pageStart) — 5 + 4);
    GetWishes(Number(pageStart) — 5);
});

Далее, на основе начальной и конечной страниц, мы .pagination создадим ссылки на страницы и .pagination UL .pagination .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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);
 
 
}

Сравнивая общее количество страниц и начальное значение страницы, мы решим, будет ли отображена ссылка на следующую кнопку.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
if ((Number(pageStart) + 5) <= pageCount) {
    var nextLink = $(‘<li/>’).append($(‘<a/>’).attr({
            ‘href’: ‘#’
        }, {
            ‘aria-label’: ‘Next’
        })
        .append($(‘<span/>’).attr(‘aria-hidden’, ‘true’).html(‘&raquo;’).click(function() {
            $(‘#hdnStart’).val(Number(pageStart) + 5);
            $(‘#hdnEnd’).val(Number(pageStart) + 5 + 4);
            GetWishes(Number(pageStart) + 5);
 
        })));
    $(‘.pagination’).append(nextLink);
}

Как видно из приведенного выше кода, при следующем нажатии кнопки мы hdnEnd значения кнопок hdnStart и hdnEnd и вызываем функцию GetWishes JavaScript.

Итак, вот последняя GetWishes JavaScript GetWishes .

001
002
003
004
005
006
007
008
009
010
011
012
013
014
015
016
017
018
019
020
021
022
023
024
025
026
027
028
029
030
031
032
033
034
035
036
037
038
039
040
041
042
043
044
045
046
047
048
049
050
051
052
053
054
055
056
057
058
059
060
061
062
063
064
065
066
067
068
069
070
071
072
073
074
075
076
077
078
079
080
081
082
083
084
085
086
087
088
089
090
091
092
093
094
095
096
097
098
099
100
101
102
103
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(‘&laquo;’));
 
                $(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(‘&raquo;’).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);
        }
    });
}

Сохраните все вышеперечисленные изменения и перезагрузите сервер. Войдите, используя действующий адрес электронной почты и пароль. Вы должны увидеть полностью функциональную нумерацию страниц для списка пожеланий пользователя.

В этой части серии мы реализовали функцию разбиения на страницы для списка пожеланий на домашней странице пользователя. Мы увидели, как получать данные с помощью хранимой процедуры MySQL и создавать нумерацию страниц с использованием этих данных, jQuery и Bootstrap.

В следующей части этого руководства мы реализуем функцию загрузки файлов в наше приложение.

Исходный код из этого урока доступен на GitHub .

Дайте нам знать ваши мысли в комментариях ниже!