Advertisement
  1. Code
  2. Python

파이썬 플라스크와 MySQL을 이용한 웹 앱 개발: 4부

Scroll to top
Read Time: 9 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 3
Creating a Web App From Scratch Using Python Flask and MySQL: Part 5

() translation by (you can also view the original English article)

이 연재 기사의 3부에서는 로그인한 사용자가 희망사항을 추가하는 데 필요한 기능을 구현했습니다. 또한 사용자가 사용자 홈 페이지에서 입력한 희망사항을 표시하는 방법도 살펴봤습니다.

이번 4부에서는 사용자가 입력한 내용을 수정하고 삭제하는 기능을 구현하겠습니다.

시작하기

먼저 깃허브(GitHub)에서 튜토리얼의 이전 내용을 복제합니다.

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

소스코드가 복제되면 프로젝트 디렉터리로 이동한 후 웹 서버를 구동합니다.

1
cd PythonFlaskMySQLApp_Part3
2
python app.py

브라우저에서 https://localhost:5002/로 이동하면 실행 중인 애플리케이션을 볼 수 있을 것입니다.

희망사항 수정하기

1단계: 수정 아이콘 표시

3부를 진행하면서 이미 우리는 jQuery를 이용해 조회된 데이터를 HTML에 바인딩하고 있습니다. 여기서는 그러한 코드를 수정해서 jQuery 템플릿을 이용해 데이터를 더 쉽게 바인딩할 것입니다. 또한 HTML에 edit 아이콘을 추가해서 희망사항을 업데이트하는 수단도 제공하겠습니다. userHome.html을 열고 jQuery 템플릿에 대한 참조를 추가합니다.

1
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jquery.templates/beta1/jquery.tmpl.js"></script>

기존 list-group div를 제거하고 다음 HTML 코드로 대체합니다.

1
<div class="row">
2
    <div class="col-md-12">
3
4
        <div class="panel-body">
5
6
            <ul id="ulist" class="list-group">
7
8
9
10
            </ul>
11
        </div>
12
13
    </div>
14
</div>

여기서는 list-group 클래스가 지정된 UL에서 데이터를 바인딩하겠습니다. HTML 본문에 나와 있는 것과 같이 listTemplate을 정의합니다.

1
<script id="listTemplate" type="text/x-jQuery-tmpl">
2
    <li class="list-group-item">
3
        <div class="checkbox">
4
            <label>
5
                ${Title}
6
            </label>

7
        </div>

8
        <div class="pull-right action-buttons">
9
            <a data-toggle="modal" data-target="#editModal"><span class="glyphicon glyphicon-pencil"></span></a>
10
           
11
        </div>

12
    </li>

13
</script>

jQuery AJAX 성공 콜백을 수정해서 데이터를 listTemplate에 바인딩합니다.

1
<script>
2
    $(function() {
3
        $.ajax({
4
            url: '/getWish',
5
            type: 'GET',
6
            success: function(res) {
7
8
                // Parse the JSON response

9
                var wishObj = JSON.parse(res);
10
                
11
                // Append to the template

12
                $('#listTemplate').tmpl(wishObj).appendTo('#ulist');
13
14
15
            },
16
            error: function(error) {
17
                console.log(error);
18
            }
19
        });
20
    });
21
</script>

또한 userHome.html에 몇 가지 스타일도 추가합니다.

1
<style>
2
    .trash {
3
        color: rgb(209, 91, 71);
4
    }
5
    .panel-body .checkbox {
6
        display: inline-block;
7
        margin: 0px;
8
    }
9
    .list-group {
10
        margin-bottom: 0px;
11
    }
12
</style>

모든 변경 사항을 저장하고 서버를 다시 시작합니다. 브라우저에서 http://localhost:5002로 이동한 후 유효한 이메일 주소와 비밀번호를 사용해 로그인합니다. 로그인하고 나면 사용자가 작성한 희망사항을 볼 수 있을 것입니다.

User Home with Edit IconUser Home with Edit IconUser Home with Edit Icon

2단계: 수정 팝업 표시

이번에는 부트스트랩(Bootstrap)을 통해 팝업을 표시해 희망사항을 수정할 수 있는 인터페이스를 제공하겠습니다. userHome.html에 부트스트랩에 대한 참조를 추가합니다.

1
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.2/js/bootstrap.min.js"></script>

참조가 포함되면 userHome.html에 다음과 같은 HTML을 추가합니다.

1
<div class="modal fade" id="editModal" tabindex="-1" role="dialog" aria-labelledby="editModalLabel" aria-hidden="true">
2
    <div class="modal-dialog">
3
        <div class="modal-content">
4
            <div class="modal-header">
5
                <button type="button" class="close" data-dismiss="modal"><span aria-hidden="true">&times;</span><span class="sr-only">Close</span>
6
                </button>
7
                <h4 class="modal-title" id="editModalLabel">Update Wish</h4>
8
            </div>
9
            <div class="modal-body">
10
                <form role="form">
11
                    <div class="form-group">
12
                        <label for="recipient-name" class="control-label">Title:</label>
13
                        <input type="text" class="form-control" id="editTitle">
14
                    </div>
15
                    <div class="form-group">
16
                        <label for="message-text" class="control-label">Description:</label>
17
                        <textarea class="form-control" id="editDescription"></textarea>
18
                    </div>
19
                </form>
20
            </div>
21
            <div class="modal-footer">
22
                <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
23
                <button type="button" id="btnUpdate" class="btn btn-primary">Update</button>
24
            </div>
25
        </div>
26
    </div>
27
</div>

위의 HTML 코드가 팝업으로 표시될 것입니다. 사용자가 edit 아이콘을 클릭하면 위의 팝업이 표시됩니다. 이미 모달 팝업을 트리거할 data-targetdata-toggle 속성을 추가해뒀습니다.

1
 <a data-toggle="modal" data-target="#editModal"><span class="glyphicon glyphicon-pencil"></span></a>

위의 변경 사항을 저장하고 앱을 다시 시작합니다. 애플리케이션에 로그인하고 나서 edit 아이콘을 클릭하면 팝업을 볼 수 있을 것입니다.

Edit Wish PopupEdit Wish PopupEdit Wish Popup

3단계: 수정 팝업 채우기

사용자가 수정 아이콘을 클릭하면 업데이트할 titledescription이 포함된 업데이트 팝업을 표시하겠습니다. 먼저 사용자가 수정 아이콘을 클릭하면 특정 희망사항 내용을 가져오기 위해 희망사항 ID가 필요합니다. 따라서 앵커 요소에 별도의 data-id 속성를 포함하도록 jQuery 템플릿 코드를 수정합니다.

1
<a data-id=${Id} onclick="Edit(this)" ><span class="glyphicon glyphicon-pencil"></span></a>

또한 Edit 메서드를 호출하는 onclick 이벤트도 추가했습니다. Edit 함수에서는 희망사항 정보를 반환하는 getWishById라는 파이썬 메서드를 호출하는 AJAX 호출을 수행합니다.

1
function Edit(elm) {
2
    $.ajax({
3
        url: '/getWishById',
4
        data: {
5
            id: $(elm).attr('data-id')
6
        },
7
        type: 'POST',
8
        success: function(res) {
9
            console.log(res);
10
        },
11
        error: function(error) {
12
            console.log(error);
13
        }
14
    });
15
}

다음으로 app.py를 열고 getWishById라는 메서드를 작성합니다. 이 메서드를 이용해 데이터베이스에서 특정 희망사항 정보를 가져오겠습니다.

1
@app.route('/getWishById',methods=['POST'])
2
def getWishById():
3
    try:
4
        if session.get('user'):
5
6
            _id = request.form['id']
7
            _user = session.get('user')
8
9
            conn = mysql.connect()
10
            cursor = conn.cursor()
11
            cursor.callproc('sp_GetWishById',(_id,_user))
12
            result = cursor.fetchall()
13
14
            wish = []
15
            wish.append({'Id':result[0][0],'Title':result[0][1],'Description':result[0][2]})
16
17
            return json.dumps(wish)
18
        else:
19
            return render_template('error.html', error = 'Unauthorized Access')
20
    except Exception as e:
21
        return render_template('error.html',error = str(e))

위 메서드에서 볼 수 있듯이 이 메서드에 희망사항 ID를 전달했으며, 메서드에서는 user IDwish ID를 이용해 데이터베이스에서 데이터를 가져옵니다. 데이터를 가져오면 해당 데이터를 리스트로 변환한 다음 JSON 데이터로 반환합니다.

다음으로 데이터베이스에서 데이터를 가져오는 데 필요한 MySQL 저장 프로시저를 만들어 봅시다.

1
DELIMITER $$
2
3
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_GetWishById`(
4
IN p_wish_id bigint,
5
In p_user_id bigint
6
)
7
BEGIN
8
select * from tbl_wish where wish_id = p_wish_id and wish_user_id = p_user_id;
9
END

위 코드는 wish IDuser ID를 이용해 특정 희망사항 정보를 구하는 저장 프로시저입니다.

변경 사항을 저장하고 서버를 다시 시작합니다. 애플리케이션에 로그인한 후 edit 아이콘을 클릭하면 브라우저 콘솔에 세부 정보가 기록됩니다.

조회된 데이터를 HTML 팝업에 바인딩하려면 먼저 수정 아이콘 앵커 태그에서 data-targetdata-toggle 속성을 제거합니다. 그런 다음 아래와 같은 코드를 Edit 자바스크립트 함수의 성공 콜백에 추가해 팝업을 채우고 트리거합니다.

1
// Parse the received JSON string

2
var data = JSON.parse(res);
3
4
//Populate the Pop up

5
$('#editTitle').val(data[0]['Title']);
6
$('#editDescription').val(data[0]['Description']);
7
8
// Trigger the Pop Up

9
$('#editModal').modal();

변경 사항을 저장하고 서버를 다시 시작합니다. 애플리케이션에 로그인하고 나서 수정 아이콘을 클릭하면 제목과 설명이 포함된 팝업이 나타납니다.

Populated Edit Pop UpPopulated Edit Pop UpPopulated Edit Pop Up

4단계: 희망사항 정보 갱신

갱신 기능을 구현하기 위해 먼저 MySQL 저장 프로시저를 만들겠습니다.

1
DELIMITER $$
2
CREATE DEFINER=`root`@`localhost` PROCEDURE `sp_updateWish`(
3
IN p_title varchar(45),
4
IN p_description varchar(1000),
5
IN p_wish_id bigint,
6
In p_user_id bigint
7
)
8
BEGIN
9
update tbl_wish set wish_title = p_title,wish_description = p_description
10
    where wish_id = p_wish_id and wish_user_id = p_user_id;
11
END$$
12
DELIMITER ;

위의 저장 프로시저에서 볼 수 있듯이 데이터베이스에 담긴 세부 사항을 갱신하기 위해 희망사항과사용자의 ID와 함께 수정 된 titledescription을 전달합니다.

다음으로 세부 사항을 갱신하는 updateWish라는 새로운 메서드를 작성하겠습니다. 다음은 updateWish 메서드입니다.

1
@app.route('/updateWish', methods=['POST'])
2
def updateWish():
3
    try:
4
        if session.get('user'):
5
            _user = session.get('user')
6
            _title = request.form['title']
7
            _description = request.form['description']
8
            _wish_id = request.form['id']
9
10
11
12
            conn = mysql.connect()
13
            cursor = conn.cursor()
14
            cursor.callproc('sp_updateWish',(_title,_description,_wish_id,_user))
15
            data = cursor.fetchall()
16
17
            if len(data) is 0:
18
                conn.commit()
19
                return json.dumps({'status':'OK'})
20
            else:
21
                return json.dumps({'status':'ERROR'})
22
    except Exception as e:
23
        return json.dumps({'status':'Unauthorized access'})
24
    finally:
25
        cursor.close()
26
        conn.close()

위의 코드에서 볼 수 있듯이 유효한 세션의 유효성을 확인한 후 전송된 데이터를 수집하고 sp_updateWish라는 저장 프로시저를 호출해서 세부 정보를 갱신합니다.

updateWish 메서드를 호출하려면 Update 버튼 클릭에 대해 이벤트를 추가해야 합니다. 따라서 업데이트 버튼의 이름을 btnUpdate로 지정하고 다음과 같이 onclick 이벤트를 추가합니다.

1
$('#btnUpdate').click(function() {
2
    $.ajax({
3
        url: '/updateWish',
4
        data: {
5
            title: $('#editTitle').val(),
6
            description: $('#editDescription').val(),
7
            id: localStorage.getItem('editId')
8
        },
9
        type: 'POST',
10
        success: function(res) {
11
            $('#editModal').modal('hide');
12
            // Re populate the grid

13
        },
14
        error: function(error) {
15
            console.log(error);
16
        }
17
    })
18
});

위의 코드에서 알 수 있듯이 localStorage에서 editId를 수집했으므로 Edit 함수에서 IDlocalStorage에 저장합니다.

1
localStorage.setItem('editId',$(elm).attr('data-id'));

getWish AJAX 호출을 함수로 감쌌으므로 데이터가 업데이트되면 이를 다시 호출할 수 있습니다.

1
function GetWishes() {
2
    $.ajax({
3
        url: '/getWish',
4
        type: 'GET',
5
        success: function(res) {
6
            var wishObj = JSON.parse(res);
7
            $('#ulist').empty();
8
            $('#listTemplate').tmpl(wishObj).appendTo('#ulist');
9
        },
10
        error: function(error) {
11
            console.log(error);
12
        }
13
    });
14
}

update AJAX 호출의 성공 콜백에서 GetWishes 함수를 호출합니다.

1
$('#btnUpdate').click(function() {
2
    $.ajax({
3
        url: '/updateWish',
4
        data: {
5
            title: $('#editTitle').val(),
6
            description: $('#editDescription').val(),
7
            id: localStorage.getItem('editId')
8
        },
9
        type: 'POST',
10
        success: function(res) {
11
            $('#editModal').modal('hide');
12
            
13
            // Re populate the grid

14
            GetWishes();
15
        },
16
        error: function(error) {
17
            console.log(error);
18
        }
19
    })
20
});

모든 변경 사항을 저장하고 서버를 다시 시작합니다. 애플리케이션에 로그인한 후 사용자가 작성한 희망사항을 수정해 봅시다.

희망사항 삭제하기

1단계: 확인 팝업 표시

userHome.html에 다음과 같은 HTML 코드를 추가합니다.

1
<div class="modal fade" id="deleteModal" tabindex="-1" role="dialog" aria-labelledby="deleteModalLabel" aria-hidden="true">
2
    <div class="modal-dialog">
3
        <div class="modal-content">
4
            <div class="modal-header" style="text-align:center;">
5
                <h4 class="modal-title" style="color:red;" id="deleteModalLabel">You are going to Delete this forever !!</h4>
6
            </div>
7
8
            <div class="modal-footer">
9
                <button type="button" class="btn btn-default" data-dismiss="modal">Cancel</button>
10
                <button type="button" class="btn btn-primary">Delete</button>
11
            </div>
12
        </div>
13
    </div>
14
</div>

다음과 같은 HTML을 추가해서 listTemplate 내에 삭제 아이콘을 추가합니다.

1
<a data-id=${Id} onclick="ConfirmDelete(this)" ><span class="glyphicon glyphicon-trash"></span></a>

위의 삭제 아이콘을 클릭했을 때 확인 팝업을 트리거하는 ConfirmDelete라는 자바스크립트 함수를 호출합니다.

1
function ConfirmDelete(elem) {
2
    localStorage.setItem('deleteId', $(elem).attr('data-id'));
3
    $('#deleteModal').modal();
4
}

변경 사항을 저장하고 서버를 다시 시작합니다. 애플리케이션에 로그인한 후 희망사항 목록에서 삭제 아이콘을 클릭하면 확인 팝업이 나타날 것입니다.

Delete Confirmation PopupDelete Confirmation PopupDelete Confirmation Popup

2단계: 희망사항 삭제

희망사항 삭제 기능을 구현하려면 먼저 희망사항을 삭제하는 MySQL 저장 프로시저를 만들어야 합니다.

1
DELIMITER $$
2
USE `BucketList`$$
3
CREATE PROCEDURE `sp_deleteWish` (
4
IN p_wish_id bigint,
5
IN p_user_id bigint
6
)
7
BEGIN
8
delete from tbl_wish where wish_id = p_wish_id and wish_user_id = p_user_id;
9
END$$
10
11
DELIMITER ;

위의 프로시저에서는 희망사항 ID와 사용자 ID를 가져와 해당 희망사항을 데이터베이스에서 삭제합니다.

다음으로 app.py 내에서 sp_deleteWish 프로시저를 호출하는 메서드를 작성하겠습니다.

희망사항 삭제를 위해 deleteWish라는 메서드를 만들겠습니다.

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

위의 메서드에서는 먼저 세션을 확인했습니다. 희망사항 ID와 사용자 ID를 이용해 사용자 세션의 유효성을 검사한 후 sp_deleteWish 저장 프로시저를 호출했습니다.

위의 deleteWish 메서드를 호출하기 위해 삭제 확인 팝업의 Delete 버튼에 onclick 이벤트를 추가합니다.

1
<button type="button" class="btn btn-primary" onclick="Delete()">Delete</button>

Delete라는 자바스크립트 함수를 만들고, 이 함수 안에서 deleteWish 파이썬 메서드에 대한 AJAX 호출을 수행합니다.

1
function Delete() {
2
    $.ajax({
3
        url: '/deleteWish',
4
        data: {
5
            id: localStorage.getItem('deleteId')
6
        },
7
        type: 'POST',
8
        success: function(res) {
9
            var result = JSON.parse(res);
10
            if (result.status == 'OK') {
11
                $('#deleteModal').modal('hide');
12
                GetWishes();
13
            } else {
14
                alert(result.status);
15
            }
16
        },
17
        error: function(error) {
18
            console.log(error);
19
        }
20
    });
21
}

위의 Delete 함수의 성공 콜백에서는 반환된 상태를 확인하고, 문제가 없을 경우 모달 팝업을 숨기고 희망사항을 다시 로드합니다.

변경 사항을 저장하고 서버를 다시 시작합니다. 애플리케이션에 로그인하고 나면 사용자 홈 페이지에서 희망사항을 삭제해 봅시다.

정리

이번 연재 기사에서는 버킷 리스트 애플리케이션의 희망사항 EditDelete 기능을 구현하는 방법을 살펴봤습니다. 다음 5부에서는 사용자 홈 목록의 페이지 처리를 구현하고 몇 가지 추가 기능을 구현하겠습니다.

이 튜토리얼의 소스코드는 깃허브에서 확인하실 수 있습니다.

아래 댓글로 여러분의 생각을 알려주세요!

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.