() 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로 이동한 후 유효한 이메일 주소와 비밀번호를 사용해 로그인합니다. 로그인하고 나면 사용자가 작성한 희망사항을 볼 수 있을 것입니다.



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">×</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-target
과 data-toggle
속성을 추가해뒀습니다.
1 |
<a data-toggle="modal" data-target="#editModal"><span class="glyphicon glyphicon-pencil"></span></a> |
위의 변경 사항을 저장하고 앱을 다시 시작합니다. 애플리케이션에 로그인하고 나서 edit
아이콘을 클릭하면 팝업을 볼 수 있을 것입니다.



3단계: 수정 팝업 채우기
사용자가 수정 아이콘을 클릭하면 업데이트할 title
과 description
이 포함된 업데이트 팝업을 표시하겠습니다. 먼저 사용자가 수정 아이콘을 클릭하면 특정 희망사항 내용을 가져오기 위해 희망사항 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 ID
와 wish 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 ID
와 user ID
를 이용해 특정 희망사항 정보를 구하는 저장 프로시저입니다.
변경 사항을 저장하고 서버를 다시 시작합니다. 애플리케이션에 로그인한 후 edit
아이콘을 클릭하면 브라우저 콘솔에 세부 정보가 기록됩니다.
조회된 데이터를 HTML 팝업에 바인딩하려면 먼저 수정 아이콘 앵커 태그에서 data-target
과 data-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(); |
변경 사항을 저장하고 서버를 다시 시작합니다. 애플리케이션에 로그인하고 나서 수정 아이콘을 클릭하면 제목과 설명이 포함된 팝업이 나타납니다.



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
와 함께 수정 된 title
과 description
을 전달합니다.
다음으로 세부 사항을 갱신하는 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
함수에서 ID
를 localStorage
에 저장합니다.
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 |
}
|
변경 사항을 저장하고 서버를 다시 시작합니다. 애플리케이션에 로그인한 후 희망사항 목록에서 삭제 아이콘을 클릭하면 확인 팝업이 나타날 것입니다.



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
함수의 성공 콜백에서는 반환된 상태를 확인하고, 문제가 없을 경우 모달 팝업을 숨기고 희망사항을 다시 로드합니다.
변경 사항을 저장하고 서버를 다시 시작합니다. 애플리케이션에 로그인하고 나면 사용자 홈 페이지에서 희망사항을 삭제해 봅시다.
정리
이번 연재 기사에서는 버킷 리스트 애플리케이션의 희망사항 Edit
및 Delete
기능을 구현하는 방법을 살펴봤습니다. 다음 5부에서는 사용자 홈 목록의 페이지 처리를 구현하고 몇 가지 추가 기능을 구현하겠습니다.
이 튜토리얼의 소스코드는 깃허브에서 확인하실 수 있습니다.
아래 댓글로 여러분의 생각을 알려주세요!