Статьи

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

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

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

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

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

1
2
cd PythonFlaskMySQLApp_Part6
python app.py

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

Мы создадим новую страницу под названием « dashboard где будут отображаться все пожелания разных пользователей. Любой пользователь может понравиться или прокомментировать пожелания, отображаемые на панели инструментов. Перейдите в папку с шаблонами и создайте файл с именем dashboard.html . Откройте dashboard.html и добавьте следующий HTML-код:

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
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
<!DOCTYPE html>
<html lang=»en»>
 
<head>
    <title>Python Flask Bucket List App</title>
 
 
    <link rel=»stylesheet» href=»https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css»>
 
    <link href=»http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css» rel=»stylesheet»>
 
   
 
</head>
 
<body>
 
    <div class=»container»>
        <div class=»header»>
            <nav>
                <ul class=»nav nav-pills pull-right»>
                    <li role=»presentation» class=»active»><a href=»#»>Dashboard</a></li>
                    <li role=»presentation»><a href=»/userHome»>My List</a></li>
                    <li role=»presentation»><a href=»/showAddWish»>Add Item</a></li>
                    <li role=»presentation»><a href=»/logout»>Logout</a></li>
                </ul>
            </nav>
            <h3 class=»text-muted»>Python Flask App</h3>
        </div>
 
        <div class=»well»>
            <div class=»row»>
                <div class=»col-sm-4 col-md-4″>
                    <div class=»thumbnail»>
                        <img alt=»100%x200″ src=»static/Uploads/bucketList.png» data-holder-rendered=»true» style=»height: 150px; width: 150px; display: block;»>
                        <div class=»caption»>
                            <h3>Bungee Jumping</h3>
                            <p>vehicula ut id elit.</p>
                            <p>
                                <button type=»button» class=»btn btn-danger btn-sm»>
                                    <span class=»glyphicon glyphicon-thumbs-up» aria-hidden=»true»>
                                </button>
                            </p>
                        </div>
                    </div>
                </div>
                <div class=»col-sm-4 col-md-4″>
                    <div class=»thumbnail»>
                        <img alt=»100%x200″ src=»static/Uploads/bucketList.png» data-holder-rendered=»true» style=»height: 150px; width: 150px; display: block;»>
                        <div class=»caption»>
                            <h3>Bungee Jumping</h3>
                            <p>vehicula ut id elit.</p>
                            <p>
                                <button type=»button» class=»btn btn-danger btn-sm»>
                                    <span class=»glyphicon glyphicon-thumbs-up» aria-hidden=»true»>
                                </button>
                            </p>
                        </div>
                    </div>
                </div>
                <div class=»col-sm-4 col-md-4″>
                    <div class=»thumbnail»>
                        <img alt=»100%x200″ src=»static/Uploads/bucketList.png» data-holder-rendered=»true» style=»height: 150px; width: 150px; display: block;»>
                        <div class=»caption»>
                            <h3>Bungee Jumping</h3>
                            <p>vehicula ut id elit.</p>
                            <p>
                                <button type=»button» class=»btn btn-danger btn-sm»>
                                    <span class=»glyphicon glyphicon-thumbs-up» aria-hidden=»true»>
                                </button>
                            </p>
                        </div>
                    </div>
                </div>
 
 
                <div class=»row»>
                    <div class=»col-sm-4 col-md-4″>
                        <div class=»thumbnail»>
                            <img alt=»100%x200″ src=»static/Uploads/bucketList.png» data-holder-rendered=»true» style=»height: 150px; width: 150px; display: block;»>
                            <div class=»caption»>
                                <h3>Bungee Jumping</h3>
                                <p>vehicula ut id elit.</p>
                                <p>
                                    <button type=»button» class=»btn btn-danger btn-sm»>
                                        <span class=»glyphicon glyphicon-thumbs-up» aria-hidden=»true»>
                                    </button>
                                </p>
                            </div>
                        </div>
                    </div>
                    <div class=»col-sm-4 col-md-4″>
                        <div class=»thumbnail»>
                            <img alt=»100%x200″ src=»static/Uploads/bucketList.png» data-holder-rendered=»true» style=»height: 150px; width: 150px; display: block;»>
                            <div class=»caption»>
                                <h3>Bungee Jumping</h3>
                                <p>vehicula ut id elit.</p>
                                <p>
                                    <button type=»button» class=»btn btn-danger btn-sm»>
                                        <span class=»glyphicon glyphicon-thumbs-up» aria-hidden=»true»>
                                    </button>
                                </p>
                            </div>
                        </div>
                    </div>
                    <div class=»col-sm-4 col-md-4″>
                        <div class=»thumbnail»>
                            <img alt=»100%x200″ src=»static/Uploads/bucketList.png» data-holder-rendered=»true» style=»height: 150px; width: 150px; display: block;»>
                            <div class=»caption»>
                                <h3>Bungee Jumping</h3>
                                <p>vehicula ut id elit.</p>
                                <p>
                                    <button type=»button» class=»btn btn-danger btn-sm»>
                                        <span class=»glyphicon glyphicon-thumbs-up» aria-hidden=»true»>
                                    </button>
                                </p>
                            </div>
                        </div>
                    </div>
                </div>
 
            </div>
 
            <footer class=»footer»>
                <p>&copy;
            </footer>
 
        </div>
</body>
 
</html>

Откройте app.py и создайте новый маршрут с именем /showDashboard . Используя этот маршрут, мы отобразим страницу панели инструментов.

1
2
3
@app.route(‘/showDashboard’)
def showDashboard():
    return render_template(‘dashboard.html’)

Измените метод /validateLogin чтобы перенаправить пользователя при успешном входе на страницу панели инструментов вместо домашней страницы пользователя.

1
return redirect(‘/showDashboard’)

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

Страница панели инструментов

Как видно на изображении выше, мы будем показывать все пожелания, созданные разными пользователями, и предоставлять другим пользователям доступ к ним.

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

01
02
03
04
05
06
07
08
09
10
11
USE `BucketList`;
DROP procedure IF EXISTS `sp_GetAllWishes`;
 
DELIMITER $$
USE `BucketList`$$
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_GetAllWishes`()
BEGIN
    select wish_id,wish_title,wish_description,wish_file_path from tbl_wish where wish_private = 0;
END$$
 
DELIMITER ;

Вышеупомянутая хранимая процедура будет получать все пожелания из tbl_wish которые не помечены как частные

Далее мы создадим новый метод Python для вызова хранимой процедуры sp_GetAllWishes . Откройте app.py и добавьте следующий код для метода getAllWishes .

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
28
@app.route(‘/getAllWishes’)
def getAllWishes():
    try:
        if session.get(‘user’):
             
            conn = mysql.connect()
            cursor = conn.cursor()
            cursor.callproc(‘sp_GetAllWishes’)
            result = cursor.fetchall()
         
 
         
            wishes_dict = []
            for wish in result:
                wish_dict = {
                        ‘Id’: wish[0],
                        ‘Title’: wish[1],
                        ‘Description’: wish[2],
                        ‘FilePath’: wish[3]}
                wishes_dict.append(wish_dict)
 
            
 
            return json.dumps(wishes_dict)
        else:
            return render_template(‘error.html’, error = ‘Unauthorized Access’)
    except Exception as e:
        return render_template(‘error.html’,error = str(e))

В приведенном выше методе мы сначала проверили допустимый сеанс пользователя, а затем создали соединение MySQL. Используя соединение MySQL conn , мы использовали курсор для вызова хранимой процедуры sp_GetAllWishes для получения необходимых данных. Как только данные были получены, мы проанализировали результат и вернули правильную строку JSON .

Мы будем вызывать вышеупомянутый метод созданный /getAllWishes при загрузке страницы панели мониторинга. Откройте dashboard.html и, используя jQuery AJAX , сделайте вызов /getAllWishes для document.ready.

01
02
03
04
05
06
07
08
09
10
11
12
$(function() {
    $.ajax({
        url: ‘/getAllWishes’,
        type: ‘GET’,
        success: function(response) {
            console.log(response);
        },
        error: function(error) {
            console.log(error);
        }
    });
})

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

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
[{
    «Description»: «Bungee Jumping»,
    «FilePath»: «static/Uploads/de5f8a10-54ea-49f4-80ce-35626277047e.jpg»,
    «Id»: 10,
    «Title»: «Bungee Jumping»
}, {
    «Description»: «Mount Everest climb»,
    «FilePath»: «static/Uploads/e3e8f7fa-6cb9-4cc3-9989-a80e5089546f.png»,
    «Id»: 11,
    «Title»: «Mount Everest climb»
}, {
    «Description»: «River Rafting»,
    «FilePath»: «static/Uploads/dff3a64c-5193-42b5-9cdb-9d67a7bbacab.png»,
    «Id»: 14,
    «Title»: «River Rafting»
}, {
    «Description»: «Deep Sea Diving»,
    «FilePath»: «static/Uploads/b0656759-c038-46b4-9529-c208aaa6bfb7.png»,
    «Id»: 15,
    «Title»: «Deep Sea Diving»
}]

Используя данные из ответа, мы заполним нашу страницу панели инструментов. Сначала удалите HTML-код между .well div из dashboard.html .

1
2
3
4
5
<div class=»well»>
 
<!— We’ll populate this dynamically —>
 
</div>

В обратном вызове успеха вызова AJAX проанализируйте response на объект JavaScript.

1
var data = JSON.parse(response);

Нам нужно будет динамически создавать HTML-код с использованием jQuery для каждого набора из трех желаний подряд. Итак, сначала давайте создадим функцию JavaScript для динамического создания HTML-кода. Вот HTML-код, который мы будем создавать динамически с помощью jQuery:

01
02
03
04
05
06
07
08
09
10
11
<div class=»col-sm-4 col-md-4″>
    <div class=»thumbnail»><img src=»static/Uploads/de5f8a10-54ea-49f4-80ce-35626277047e.jpg» data-holder-rendered=»true» style=»height: 150px; width: 150px; display: block»>
        <div class=»caption»>
            <h3>Testing App</h3>
            <p>hello</p>
            <p>
                <button type=»button» class=»btn btn-danger btn-sm»><span class=»glyphicon glyphicon-thumbs-up» aria-hidden=»true»>
            </p>
        </div>
    </div>
</div>

Мы CreateThumb функцию JavaScript CreateThumb . В этой функции мы создадим элементы HTML и добавим их к своим родительским элементам, чтобы получить код HTML, показанный выше.

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
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
function CreateThumb(id,title, desc, filepath) {
   
    var mainDiv = $(‘<div>’).attr(‘class’, ‘col-sm-4 col-md-4’);
   
    var thumbNail = $(‘<div>’).attr(‘class’, ‘thumbnail’);
                                     
    var img = $(‘<img>’).attr({
        ‘src’: filepath,
        ‘data-holder-rendered’: true,
        ‘style’: ‘height: 150px;
    });
   
    var caption = $(‘<div>’).attr(‘class’, ‘caption’);
   
    var title = $(‘<h3>’).text(title);
   
    var desc = $(‘<p>’).text(desc);
 
 
    var p = $(‘<p>’);
   
    var btn = $(‘<button>’).attr({
        ‘id’: ‘btn_’ + id,
        ‘type’: ‘button’,
        ‘class’: ‘btn btn-danger btn-sm’
    });
   
    var span = $(‘<span>’).attr({
        ‘class’: ‘glyphicon glyphicon-thumbs-up’,
        ‘aria-hidden’: ‘true’
    });
 
    p.append(btn.append(span));
 
 
 
    caption.append(title);
    caption.append(desc);
    caption.append(p);
 
    thumbNail.append(img);
    thumbNail.append(caption);
    mainDiv.append(thumbNail);
    return mainDiv;
 
 
}

Приведенный выше код довольно прост, поэтому я не буду вдаваться в подробности.

Продвигаясь вперед, мы будем повторять проанализированный ответ JSON и создадим HTML- CreateThumb функции CreateThumb . Мы планируем отображать три желания в строке. Поэтому мы проверим это и создадим новую строку каждый раз для трех желаний. Добавьте следующий код к обратному вызову AJAX в dashboard.html .

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
var itemsPerRow = 0;
var div = $(‘<div>’).attr(‘class’, ‘row’);
for (var i = 0; i < data.length; i++) {
     
 
    if (itemsPerRow < 3) {
       
        if (i == data.length — 1) {
            div.append(CreateThumb(data[i].Id,data[i].Title, data[i].Description, data[i].FilePath));
            $(‘.well’).append(div);
        } else {
            div.append(CreateThumb(data[i].Id,data[i].Title, data[i].Description, data[i].FilePath));
            itemsPerRow++;
        }
    } else {
        $(‘.well’).append(div);
        div = $(‘<div>’).attr(‘class’, ‘row’);
        div.append(CreateThumb(data[i].Id,data[i].Title, data[i].Description, data[i].FilePath));
        if (i == data.length — 1) {
            $(‘.well’).append(div);
        }
        itemsPerRow = 1;
    }
     
}

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

Далее, давайте добавим событие click к кнопкам like под миниатюрами пожеланий. Поскольку мы динамически создали кнопки, нам нужно прикрепить событие click к кнопкам с помощью метода jQuery on .

1
2
3
$(document).on(‘click’, ‘[id^=»btn_»]’, function() {
    // Event function can be added here
});

Давайте начнем с создания таблицы, которая будет отслеживать лайки, собранные конкретным желанием. Создайте таблицу с именем tbl_likes .

1
2
3
4
5
6
CREATE TABLE `BucketList`.`tbl_likes` (
 `wish_id` INT NOT NULL,
 `like_id` INT NOT NULL AUTO_INCREMENT,
 `user_id` INT NULL,
 `wish_like` INT NULL DEFAULT 0 ;
 PRIMARY KEY (`like_id`));

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

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
DELIMITER $$
 
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_AddUpdateLikes`(
    p_wish_id int,
    p_user_id int,
    p_like int
)
BEGIN
    if (select exists (select 1 from tbl_likes where wish_id = p_wish_id and user_id = p_user_id)) then
 
        update tbl_likes set wish_like = p_like where wish_id = p_wish_id and user_id = p_user_id;
         
    else
         
        insert into tbl_likes(
            wish_id,
            user_id,
            wish_like
        )
        values(
            p_wish_id,
            p_user_id,
            p_like
        );
 
    end if;
END

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

Давайте создадим метод Python для вызова вышеуказанной хранимой процедуры.

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
@app.route(‘/addUpdateLike’,methods=[‘POST’])
def addUpdateLike():
    try:
        if session.get(‘user’):
            _wishId = request.form[‘wish’]
            _like = request.form[‘like’]
            _user = session.get(‘user’)
            
 
            conn = mysql.connect()
            cursor = conn.cursor()
            cursor.callproc(‘sp_AddUpdateLikes’,(_wishId,_user,_like))
            data = cursor.fetchall()
 
            if len(data) is 0:
                conn.commit()
                return json.dumps({‘status’:’OK’})
            else:
                return render_template(‘error.html’,error = ‘An error occurred!’)
 
        else:
            return render_template(‘error.html’,error = ‘Unauthorized Access’)
    except Exception as e:
        return render_template(‘error.html’,error = str(e))
    finally:
        cursor.close()
        conn.close()

Это метод Python, который будет вызывать хранимую процедуру sp_AddUpdateLikes . В этом методе мы проверили допустимый сеанс пользователя, а затем передали желаемый ID и статус статуса хранимой процедуре обновления. Когда пользователь нажимает кнопку « /addUpdateLike нравится», нам нужно вызвать метод Python /addUpdateLike . Поэтому добавьте следующий код в функцию события like нажатия кнопки в dashboard.html .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
$(document).on(‘click’, ‘[id^=»btn_»]’, function() {
    $.ajax({
        url: ‘/addUpdateLike’,
        method: ‘POST’,
        data: {
            wish: $(this).attr(‘id’).split(‘_’)[1],
            like: 1
        },
        success: function(response) {
            console.log(response);
        },
        error: function(error) {
            console.log(error);
        }
    });
});

В настоящее время мы жестко закодировали значение как в приведенном выше вызове. Сохраните изменения и перезапустите сервер. Войдите в приложение и нажмите кнопку «Мне нравится» под любым желаемым эскизом. Теперь проверьте tbl_likes и у вас должна быть запись там.

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

Опубликуйте свои предложения или исправления в поле для комментариев ниже. Исходный код из этого урока доступен на GitHub .