Notice
Recent Posts
Recent Comments
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | |||
5 | 6 | 7 | 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 |
19 | 20 | 21 | 22 | 23 | 24 | 25 |
26 | 27 | 28 | 29 | 30 | 31 |
Tags
- 데이터베이스
- sql
- db
- 스프링
- BOJ
- 오라클
- 알고리즘
- spring
- java
- mysql
- rdbms
- 플라스크
- TIL
- 이클립스
- eclipse
- database
- javascript
- 자바
- jQuery
- Oracle
- 웹프로그래밍
- 파이썬
- flask
- 링크
- mybatis
- 에러
- Git
- 백준
- 자바스크립트
- PYTHON
Archives
- Today
- Total
기록과 정리의 공간
[프로젝트] Flask로 게시판 만들기 - 6 본문
Flask로 게시판 만들기 - 6 (참고 강의 링크-인프런 강의)
(공부 하며 기록이 필요한 부분들만 정리함)
- 개발 환경 : windows 10 / Python 3.8.1 / vscode
- 로그인한 유저만 글쓰기 가능하게 하기
- 글 수정 기능 추가하기
- 글 삭제 기능 추가하기
- 글 조회수 증가 시키기
1. 로그인한 유저만 글쓰기 가능하게 하기
- 이 포스트와 이어짐
- 글쓰기 버튼을 누르면 로그인한 사용자에 한하여 글쓰기 페이지로 이동하고, 로그인되어 있지 않다면 로그인 페이지로 이동하게 한다. 로그인이 성공하면, 로그인 전에 사용자가 요청했던 페이지로 이동시키도록 한다.
- 데코레이터 활용(with functools모듈) : 글쓰기 기능 뿐만 아니라 기타 기능 사용을 위해 유저에게 로그인을 요구하기 위해, 함수마다 로그인 요구 코드를 일일이 작성하는 것은 굉장히 번거로운 일이므로 login_required라는 이름으로 데코레이터를 만들어 필요한 함수에 사용함.
- 로그인이 성공하면, 로그인 하기 전에 사용자가 요청했던 페이지로 이동시키기 : 데코레이터의 request.url은 사용자가 요청한 페이지의 url을 가리킨다.(즉, 여기에서는 글쓰기 페이지를 의미함)
- 세션 객체 활용 : session.get()를 이용해, 사용자의 로그인 여부를 확인한다.
- member_login함수에서 유저가 로그인할 경우, session객체의 'id'라는 키에 해당 유저의 member컬렉션의 '_id'값(이는 중복이 없는 고유의 값임)을 저장하도록 했다. 따라서, session.get('id')를 통해 이 값이 None인지 아닌지를 확인하면, 로그인 여부를 확인할 수 있다.
- login.html : next_url값이 존재한다면 input 태그의 type을 hidden으로 하여, form이 submit될 때 next_url값도 함께 submit되도록 함. (html - input태그 hidden 속성)
- 아래 코드 블럭들의 주석참고
- board_wirte함수에서 post딕셔너리에 writer_id라는 키를 추가하여 여기에 session.get("id")을 저장하도록 한다. 이는 추후에 글수정, 삭제 시 본인이 작성한 글에 대해서만 수정,삭제가 가능하도록 하기 위함이다.
# 데코레이터 작성
from functools import wraps
def login_required(f):
@wraps(f)
def deco_func(*args, **kwargs):
# 로그인 여부 확인
if session.get("id") is None:
return redirect(url_for("member_login", next_url=request.url))
return f(*args, **kwargs)
return deco_func
@app.route("/write", methods=["GET", "POST"])
@login_required # 데코레이터 사용
def board_write():
(중략)
post = {
"name": name,
"title": title,
"contents": contents,
"pubdate": current_utc_time,
# 글 삭제나 수정 시, 본인글만 삭제,수정할 수 있도록 아래 값을 저장
"writer_id": session.get("id"),
"view": 0,
}
<!-- login.html -->
<form name="form" action="/login" method="POST">
<!-- 바로 아래 코드블럭의 #1에서 넘긴 next_url을 가리킴 -->
{% if next_url %}
<input type="hidden" name="next_url" value="{{next_url}}">
{% endif %}
(생략)
</form>
@app.route("/login", methods=["GET", "POST"])
def member_login():
if request.method == "POST":
email = request.form.get("email")
password = request.form.get("pass")
#2 - login.html에서 hidden으로 넘긴 next_url값 가져오기
next_url = request.form.get("next_url")
if email == "" or password == "":
flash("입력되지 않은 값이 있습니다!")
return render_template("login.html")
members = mongo.db.members
data = members.find_one({"email": email})
if data is None:
flash("회원 정보가 없습니다!")
return redirect(url_for("member_login"))
else:
if data.get("pass") == password:
session["email"] = email
session["name"] = data.get("name")
session["id"] = str(data.get("_id"))
session.permanet = True
#3 - 로그인이 성공할 경우, #2에서 가져온 next_url값이 존재하면 해당 값으로 redirect시킴
# 그게 아니라면 그냥 글목록 페이지로 이동시킴
if next_url is not None:
return redirect(next_url)
return redirect(url_for('board_list'))
else:
flash("비밀번호가 일치하지 않습니다!")
return redirect(url_for("member_login"))
return ""
else:
#0 - 글쓰기 버튼을 누르면 로그인되어 있지 않을 경우,
# board_write함수에 사용한 login_requried 데코레이터에 의해 next_url=request.rul값이 넘어옴
next_url = request.args.get("next_url", type=str)
if next_url is not None:
#1 - login.html에 next_url값을 넘김
return render_template("login.html", next_url=next_url)
else:
return render_template("login.html")
2. 글 수정 기능 추가하기
- view.html :현재 session["id"]값과 현재 글의 writer_id값이 (위 1번에서 board_write함수의 post 딕셔너리에 추가한) 동일한지 확인하여 같다면 글수정/글삭제 버튼이 보여지도록 한다.
- board_edit함수 : idx값은 view.html에서 넘겨준 값임. (현재 글의 '_id'값) view.html에서와 마찬가지로 session객체를 이용해 현재 로그인된 사용자가 글 작성자와 일치하는지 확인한다. 일치한다면 edit.html을 렌더링하는데, data값을 edit.html로 넘겨준다.
- edit.html : write.html과 동일한 코드에다가 제목과 내용 부분의 input태그에 수정 전의 제목과 내용이 보여지도록 value속성을 추가했다.
<!-- view.html -->
{% with messages = get_flashed_messages() %}
{% if messages %}
<script>
alert("{{messages[-1]}}")
</script>
{% endif %}
{% endwith %}
<html>
(중략)
{% if session["id"] == result.writer_id %}
<a href="{{url_for('board_edit', idx=result.id)}}">글수정</a>
<a href="{{url_for('board_delete', idx=result.id)}}">글삭제</a>
{% endif %}
</html>
# board_edit함수
@app.route("/edit/<idx>", methods=["GET", "POST"])
def board_edit(idx):
board = mongo.db.board
data = board.find_one({"_id": ObjectId(idx)})
if request.method == "GET":
if data is None:
flash("해당 게시물이 존재하지 않습니다.")
return redirect(url_for("lists"))
else:
if session.get("id") == data.get("writer_id"):
return render_template("edit.html", data=data)
else:
flash("글 수정 권한이 없습니다.")
return redirect(url_for("board_list"))
else:
title = request.form.get("title")
contents = request.form.get("contents")
# 또 한번 더 확인,
if session.get("id") == data.get('writer_id'):
board.update_one({"_id": ObjectId(idx)}, {
"$set": {
"title": title,
"contents": contents,
}
})
flash("수정되었습니다.")
return redirect(url_for("board_view", idx=idx))
else:
flash("글 수정 권한이 없습니다.")
return redirect(url_for("board_list"))
<!-- edit.html -->
<html>
<style>
table {
border: 1px solid black;
}
</style>
<body>
<table>
<form name="form" method="POST" action="/edit/{{data._id}}">
<tr>
<td>작성자</td>
<td><input type="text" name="name" value="{{session['name']}}" readonly></td>
</tr>
<tr>
<td>제목</td>
<td><input type="text" name="title" value={{data.title}}></td>
</tr>
<tr>
<td>내용</td>
<td><textarea name="contents">{{data.contents}}</textarea></td>
</tr>
<tr>
<td colspan="2"><input type="submit"></td>
</tr>
</form>
</table>
</body>
</html>
3. 글 삭제 기능 추가하기
- 2번 참고
@app.route("/delete/<idx>")
def board_delete(idx):
board = mongo.db.board
data = board.find_one({"_id": ObjectId(idx)})
if session.get("id") == data.get("writer_id"):
board.delete_one({"_id": ObjectId(idx)})
flash("삭제 되었습니다.")
else:
flash("삭제 권한이 없습니다.")
return redirect(url_for("board_list"))
4. 글 조회수 증가 시키기
게시물을 클릭할 때 마다 조회수가 1씩 증가되도록 구현함.
board_view함수 : find_one함수 대신 find_one_and_update함수를 사용하여 데이터를 찾아옴과 동시에 update할 수 있도록 한다. $inc 연산자(MongoDB - $inc)를 사용하여 view필드의 값을 1증가 시킨다. 중요한 것은 return_document옵션을 True로 하여 인자로 넘겨줘야한다는 것이다.
- pymongo - find_one_and_update : find_one_and_update함수는 기본적으로 update가 되기 전의 document를 리턴한다. udpate된 후의 document를 리턴받고 싶다면, return_document=True를 인자로 넘겨주면 된다.
@app.route("/view/<idx>")
def board_view(idx):
# idx = request.args.get("idx")
if idx is not None:
page = request.args.get('page')
search = request.args.get('search')
keyword = request.args.get('keyword')
board = mongo.db.board
# 조회수 증가시키기
data = board.find_one_and_update({'_id': ObjectId(idx)}, {"$inc": {"view": 1}}, return_document=True)
if data is not None:
result = {
'id': data.get('_id'),
'name': data.get('name'),
'title': data.get('title'),
'contents': data.get('contents'),
'pubdate': data.get('pubdate'),
'view': data.get('view'),
'writer_id': data.get('writer_id', "")
}
return render_template('view.html', result=result, page=page, search=search, keyword=keyword)
return abort(404)
'프로젝트 > 게시판1' 카테고리의 다른 글
[프로젝트] Flask로 게시판 만들기 - 5 (0) | 2020.08.07 |
---|---|
[프로젝트] Flask로 게시판 만들기 - 4 (1) | 2020.08.04 |
[프로젝트] Flask로 게시판 만들기 - 3 (1) | 2020.08.01 |
[프로젝트] Flask로 게시판 만들기 - 2 (0) | 2020.07.29 |
[프로젝트] Flask로 게시판 만들기 - 1 (0) | 2020.07.29 |
Comments