Advertisement
  1. Code
  2. Coding Fundamentals
  3. Databases & SQL

Creating a Web App From Scratch Using Python Flask and MySQL: Part 7

Scroll to top
Read Time: 11 min
This post is part of a series called Creating a Web App From Scratch Using Python Flask and MySQL.
Creating a Web App From Scratch Using Python Flask and MySQL: Part 6
Creating a Web App From Scratch Using Python Flask and MySQL: Part 8

In the previous part of this series, we implemented image upload functionality for the users while adding a wish. We also added a few more options related to a user's wish on the Add Wish page. In this tutorial, we'll take it to the next level by implementing the functionality to like a particular wish.

Getting Started 

Let's start by cloning the previous part of the tutorial from GitHub.

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

Once the source code has been cloned, navigate to the project directory and start the web server. 

1
cd PythonFlaskMySQLApp_Part6
2
python app.py

Point your browser to http://localhost:5002/ and you should have the application running.

Creating the Dashboard UI

We'll be creating a new page called dashboard where all the wishes from different users will be displayed. Any user can like or comment on the wishes displayed in the dashboard. So navigate to the templates folder and create a file called dashboard.html. Open up dashboard.html and add the following HTML code:

1
<!DOCTYPE html>
2
<html lang="en">
3
4
<head>
5
    <title>Python Flask Bucket List App</title>
6
7
8
    <link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/css/bootstrap.min.css">
9
10
    <link href="http://getbootstrap.com/examples/jumbotron-narrow/jumbotron-narrow.css" rel="stylesheet">
11
12
  
13
14
</head>
15
16
<body>
17
18
    <div class="container">
19
        <div class="header">
20
            <nav>
21
                <ul class="nav nav-pills pull-right">
22
                    <li role="presentation" class="active"><a href="#">Dashboard</a></li>
23
                    <li role="presentation"><a href="/userHome">My List</a></li>
24
                    <li role="presentation"><a href="/showAddWish">Add Item</a></li>
25
                    <li role="presentation"><a href="/logout">Logout</a></li>
26
                </ul>
27
            </nav>
28
            <h3 class="text-muted">Python Flask App</h3>
29
        </div>
30
31
        <div class="well">
32
            <div class="row">
33
                <div class="col-sm-4 col-md-4">
34
                    <div class="thumbnail">
35
                        <img alt="100%x200" src="static/Uploads/bucketList.png" data-holder-rendered="true" style="height: 150px; width: 150px; display: block;">
36
                        <div class="caption">
37
                            <h3>Bungee Jumping</h3>
38
                            <p>vehicula ut id elit.</p>
39
                            <p>
40
                                <button type="button" class="btn btn-danger btn-sm">
41
                                    <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
42
                                </button>
43
                            </p>
44
                        </div>
45
                    </div>
46
                </div>
47
                <div class="col-sm-4 col-md-4">
48
                    <div class="thumbnail">
49
                        <img alt="100%x200" src="static/Uploads/bucketList.png" data-holder-rendered="true" style="height: 150px; width: 150px; display: block;">
50
                        <div class="caption">
51
                            <h3>Bungee Jumping</h3>
52
                            <p>vehicula ut id elit.</p>
53
                            <p>
54
                                <button type="button" class="btn btn-danger btn-sm">
55
                                    <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
56
                                </button>
57
                            </p>
58
                        </div>
59
                    </div>
60
                </div>
61
                <div class="col-sm-4 col-md-4">
62
                    <div class="thumbnail">
63
                        <img alt="100%x200" src="static/Uploads/bucketList.png" data-holder-rendered="true" style="height: 150px; width: 150px; display: block;">
64
                        <div class="caption">
65
                            <h3>Bungee Jumping</h3>
66
                            <p>vehicula ut id elit.</p>
67
                            <p>
68
                                <button type="button" class="btn btn-danger btn-sm">
69
                                    <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
70
                                </button>
71
                            </p>
72
                        </div>
73
                    </div>
74
                </div>
75
76
77
                <div class="row">
78
                    <div class="col-sm-4 col-md-4">
79
                        <div class="thumbnail">
80
                            <img alt="100%x200" src="static/Uploads/bucketList.png" data-holder-rendered="true" style="height: 150px; width: 150px; display: block;">
81
                            <div class="caption">
82
                                <h3>Bungee Jumping</h3>
83
                                <p>vehicula ut id elit.</p>
84
                                <p>
85
                                    <button type="button" class="btn btn-danger btn-sm">
86
                                        <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
87
                                    </button>
88
                                </p>
89
                            </div>
90
                        </div>
91
                    </div>
92
                    <div class="col-sm-4 col-md-4">
93
                        <div class="thumbnail">
94
                            <img alt="100%x200" src="static/Uploads/bucketList.png" data-holder-rendered="true" style="height: 150px; width: 150px; display: block;">
95
                            <div class="caption">
96
                                <h3>Bungee Jumping</h3>
97
                                <p>vehicula ut id elit.</p>
98
                                <p>
99
                                    <button type="button" class="btn btn-danger btn-sm">
100
                                        <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
101
                                    </button>
102
                                </p>
103
                            </div>
104
                        </div>
105
                    </div>
106
                    <div class="col-sm-4 col-md-4">
107
                        <div class="thumbnail">
108
                            <img alt="100%x200" src="static/Uploads/bucketList.png" data-holder-rendered="true" style="height: 150px; width: 150px; display: block;">
109
                            <div class="caption">
110
                                <h3>Bungee Jumping</h3>
111
                                <p>vehicula ut id elit.</p>
112
                                <p>
113
                                    <button type="button" class="btn btn-danger btn-sm">
114
                                        <span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span>
115
                                    </button>
116
                                </p>
117
                            </div>
118
                        </div>
119
                    </div>
120
                </div>
121
122
            </div>
123
124
            <footer class="footer">
125
                <p>&copy; Company 2015</p>
126
            </footer>
127
128
        </div>
129
</body>
130
131
</html>

Open up app.py and create a new route called /showDashboard. Using this route we'll render the dashboard page.

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

Modify the /validateLogin method to redirect the user on successful sign-in to the dashboard page instead of the user home page.

1
return redirect('/showDashboard')

Save the above changes and restart the server. Point your browser to http://localhost:50002 and sign in using a valid email address and password. Once signed in, you should be able to see the dashboard page.

Dashboard PageDashboard PageDashboard Page

As seen in the image above, we'll be showing all the wishes created by different users and giving access to other users to like them.

Populate the Dashboard

First, we need to fetch the data from the database to populate the dashboard. So let's create a stored procedure to get the wishes created by users.

1
USE `BucketList`;
2
DROP procedure IF EXISTS `sp_GetAllWishes`;
3
4
DELIMITER $$
5
USE `BucketList`$$
6
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_GetAllWishes`()
7
BEGIN
8
    select wish_id,wish_title,wish_description,wish_file_path from tbl_wish where wish_private = 0;
9
END$$
10
11
DELIMITER ;
12

The above stored procedure will fetch all the wishes from tbl_wish which are not marked as private.

Next, we'll create a new Python method to call the stored procedure sp_GetAllWishes. Open app.py and add the following code for the getAllWishes method.

1
@app.route('/getAllWishes')
2
def getAllWishes():
3
    try:
4
        if session.get('user'):
5
            
6
            conn = mysql.connect()
7
            cursor = conn.cursor()
8
            cursor.callproc('sp_GetAllWishes')
9
            result = cursor.fetchall()
10
        
11
12
	    
13
            wishes_dict = []
14
            for wish in result:
15
                wish_dict = {
16
                        'Id': wish[0],
17
                        'Title': wish[1],
18
                        'Description': wish[2],
19
                        'FilePath': wish[3]}
20
                wishes_dict.append(wish_dict)		
21
22
           
23
24
            return json.dumps(wishes_dict)
25
        else:
26
            return render_template('error.html', error = 'Unauthorized Access')
27
    except Exception as e:
28
        return render_template('error.html',error = str(e))

In the above method, we have first checked for a valid user session and then created a MySQL connection. Using the MySQL connection conn, we used a cursor to call the stored procedure sp_GetAllWishes to get the required data. Once the data has been fetched, we have parsed the result and returned a proper JSON string.

We'll call the above created /getAllWishes method when the dashboard page loads. Open dashboard.html and, using jQuery AJAX, make a call to /getAllWishes on document.ready.

1
$(function() {
2
    $.ajax({
3
        url: '/getAllWishes',
4
        type: 'GET',
5
        success: function(response) {
6
            console.log(response);
7
        },
8
        error: function(error) {
9
            console.log(error);
10
        }
11
    });
12
})

Save the above changes and restart the server. Once logged in to the application, check your browser console and you should be able to view the data fetched from the database.

1
[{
2
    "Description": "Bungee Jumping",
3
    "FilePath": "static/Uploads/de5f8a10-54ea-49f4-80ce-35626277047e.jpg",
4
    "Id": 10,
5
    "Title": "Bungee Jumping"
6
}, {
7
    "Description": "Mount Everest climb",
8
    "FilePath": "static/Uploads/e3e8f7fa-6cb9-4cc3-9989-a80e5089546f.png",
9
    "Id": 11,
10
    "Title": "Mount Everest climb"
11
}, {
12
    "Description": "River Rafting",
13
    "FilePath": "static/Uploads/dff3a64c-5193-42b5-9cdb-9d67a7bbacab.png",
14
    "Id": 14,
15
    "Title": "River Rafting"
16
}, {
17
    "Description": "Deep Sea Diving",
18
    "FilePath": "static/Uploads/b0656759-c038-46b4-9529-c208aaa6bfb7.png",
19
    "Id": 15,
20
    "Title": "Deep Sea Diving"
21
}]

Using the data from the response, we'll populate our dashboard page. First, remove the HTML code between the .well div from dashboard.html.

1
<div class="well">
2
3
<!-- We'll populate this dynamically -->
4
5
</div>

In the success callback of the AJAX call, parse the response to a JavaScript object.

1
var data = JSON.parse(response);

We'll need to create the thumbnail HTML code dynamically using jQuery for each set of three wishes in a row. So first let's create a JavaScript function to create the HTML code dynamically. Here is the HTML code that we'll be creating dynamically using jQuery:

1
<div class="col-sm-4 col-md-4">
2
    <div class="thumbnail"><img src="static/Uploads/de5f8a10-54ea-49f4-80ce-35626277047e.jpg" data-holder-rendered="true" style="height: 150px; width: 150px; display: block">
3
        <div class="caption">
4
            <h3>Testing App</h3>
5
            <p>hello</p>
6
            <p>
7
                <button type="button" class="btn btn-danger btn-sm"><span class="glyphicon glyphicon-thumbs-up" aria-hidden="true"></span></button>
8
            </p>
9
        </div>
10
    </div>
11
</div>

We'll name the JavaScript function CreateThumb. In this function, we'll create the HTML elements and append them to their parent elements to get the HTML code shown above.

1
function CreateThumb(id,title, desc, filepath) {
2
  
3
    var mainDiv = $('<div>').attr('class', 'col-sm-4 col-md-4');
4
  
5
    var thumbNail = $('<div>').attr('class', 'thumbnail');
6
                                    
7
    var img = $('<img>').attr({
8
        'src': filepath,
9
        'data-holder-rendered': true,
10
        'style': 'height: 150px; width: 150px; display: block'
11
    });
12
  
13
    var caption = $('<div>').attr('class', 'caption');
14
  
15
    var title = $('<h3>').text(title);
16
  
17
    var desc = $('<p>').text(desc);
18
19
20
    var p = $('<p>');
21
  
22
    var btn = $('<button>').attr({
23
        'id': 'btn_' + id, 
24
        'type': 'button',
25
        'class': 'btn btn-danger btn-sm'
26
    });
27
  
28
    var span = $('<span>').attr({
29
        'class': 'glyphicon glyphicon-thumbs-up',
30
        'aria-hidden': 'true'
31
    });
32
33
    p.append(btn.append(span));
34
35
36
37
    caption.append(title);
38
    caption.append(desc);
39
    caption.append(p);
40
41
    thumbNail.append(img);
42
    thumbNail.append(caption);
43
    mainDiv.append(thumbNail);
44
    return mainDiv;
45
46
47
}

The above code is quite straightforward so I won't be going into the details.

Moving forward, we'll iterate the parsed JSON response and create the HTML using the CreateThumb function. We plan to display three wishes per row. So we'll check for that and create a new row each time for three wishes. Add the following code to the success callback of the AJAX call in dashboard.html.

1
var itemsPerRow = 0;
2
var div = $('<div>').attr('class', 'row');
3
for (var i = 0; i < data.length; i++) {
4
    
5
6
    if (itemsPerRow < 3) {
7
      
8
        if (i == data.length - 1) {
9
            div.append(CreateThumb(data[i].Id,data[i].Title, data[i].Description, data[i].FilePath));
10
            $('.well').append(div);
11
        } else {
12
            div.append(CreateThumb(data[i].Id,data[i].Title, data[i].Description, data[i].FilePath));
13
            itemsPerRow++;
14
        }
15
    } else {
16
        $('.well').append(div);
17
        div = $('<div>').attr('class', 'row');
18
        div.append(CreateThumb(data[i].Id,data[i].Title, data[i].Description, data[i].FilePath));
19
        if (i == data.length - 1) {
20
            $('.well').append(div);
21
        }
22
        itemsPerRow = 1;
23
    }
24
    
25
}

Save the changes and restart the server. Sign in to the application and when on the dashboard page, you should be able to view the wishes added by different users, with an option to like them.

Next, let's add a click event to the like buttons under the wishes thumbnails. Since we have dynamically created the buttons, we'll need to attach the click event to the buttons using the jQuery on method. 

1
$(document).on('click', '[id^="btn_"]', function() {
2
    // Event function can be added here

3
});

Implementing Like Functionality

Let's start by creating a table which will keep track of the likes a particular wish has garnered. Create a table called tbl_likes

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

Now whenever a user likes or dislikes a particular wish, we'll update this table. Let's create a MySQL stored procedure to update the above table.

1
DELIMITER $$
2
3
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_AddUpdateLikes`(
4
    p_wish_id int,
5
	p_user_id int,
6
	p_like int
7
)
8
BEGIN
9
	if (select exists (select 1 from tbl_likes where wish_id = p_wish_id and user_id = p_user_id)) then
10
11
		update tbl_likes set wish_like = p_like where wish_id = p_wish_id and user_id = p_user_id;
12
		
13
	else
14
		
15
		insert into tbl_likes(
16
			wish_id,
17
			user_id,
18
			wish_like
19
		)
20
		values(
21
			p_wish_id,
22
			p_user_id,
23
			p_like
24
		);
25
26
	end if;
27
END

In this stored procedure, we have simply checked if the person has already liked the wish or not. If he or she has already liked, then we have updated that like entry or added a new one.

Let's create a Python method to call the above stored procedure.

1
@app.route('/addUpdateLike',methods=['POST'])
2
def addUpdateLike():
3
    try:
4
        if session.get('user'):
5
            _wishId = request.form['wish']
6
            _like = request.form['like']
7
            _user = session.get('user')
8
           
9
10
            conn = mysql.connect()
11
            cursor = conn.cursor()
12
            cursor.callproc('sp_AddUpdateLikes',(_wishId,_user,_like))
13
            data = cursor.fetchall()
14
15
            if len(data) is 0:
16
                conn.commit()
17
                return json.dumps({'status':'OK'})
18
            else:
19
                return render_template('error.html',error = 'An error occurred!')
20
21
        else:
22
            return render_template('error.html',error = 'Unauthorized Access')
23
    except Exception as e:
24
        return render_template('error.html',error = str(e))
25
    finally:
26
        cursor.close()
27
        conn.close()

This is the Python method which will call the stored procedure sp_AddUpdateLikes. In this method we have checked for a valid user session and then passed the wish ID and like status to the stored procedure for update. When the user clicks the like button, we need to call the Python method /addUpdateLike. So add the following code to the like button click event function in dashboard.html

1
$(document).on('click', '[id^="btn_"]', function() {
2
    $.ajax({
3
        url: '/addUpdateLike',
4
        method: 'POST',
5
        data: {
6
            wish: $(this).attr('id').split('_')[1],
7
            like: 1
8
        },
9
        success: function(response) {
10
            console.log(response);
11
        },
12
        error: function(error) {
13
            console.log(error);
14
        }
15
    });
16
});

For the time being, we have hard-coded the value of like in the above call. So save the changes and restart the server. Sign in to the application and click on the like button under any wish thumbnail. Now check tbl_likes and you should have an entry in there.

Conclusion

In this part of the tutorial, we populated the dashboard page of our application with the wishes created by different users. We also attached a like button to each so that users can like a particular wish. In the next part, we'll see how to toggle the like display and show the total number of likes received by a particular wish.

Post your suggestions or any corrections in the comment box below. Source code from this tutorial is available on GitHub.

Advertisement
Did you find this post useful?
Want a weekly email summary?
Subscribe below and we’ll send you a weekly email summary of all new Code tutorials. Never miss out on learning about the next big thing.
Advertisement
Looking for something to help kick start your next project?
Envato Market has a range of items for sale to help get you started.