✏️ 이전 내용
지난 포스팅에서는 flask 서버를 통해 로그인과 회원가입을 하는 코드에 대해 소개를 했다.
이번에는 추가적으로 유저가 포스팅을 하고, 포스팅 리스트들을 보는 코드를 작성한다.
(이 글은 Firebase와 Flask 로그인/회원가입 포스터를 봤다는 전제로 작성된다.)
📚포스터 내용
이번 포스터에서는 flask로 간단하게 포스터를 작성하고 글 목록을 확인하는 기능을 만들어본다.
(CSS/JS 부분은 기능 구현에 필수가 아니므로 생략)
코드 진행 순서대로 포스팅을 해보려 했는데, 너무 복잡해져서 핵심 부분만 쓴다.
🎄파일 tree 구조
│ app.py
│ DB_handler.py
│ README.md
│
├─auth
│ firebaseAuth.json
│
├─static
│ └─image
│ └─css
└─templates
base.html
index.html
login.html
post_detail.html
post_list.html
signin.html
user_detail.html
write_post.html
(기존 파일)
- app.py : flask 서버 구현
- DB_handler.py : firebase 클래스 / 객체 생성
- firebaseAuth.json : firebase SDK 키
- base.html : 코드 공통 부분
- index.html : 시작 페이지
- login.html : 로그인 페이지
- signin.html : 회원가입 페이지
(+ 새로 추가된 파일)
- write_post.html : 포스터 작성
- post_list.html : 포스터 목록들
- post_detail.html : 포스터 세부 사항
- user_detail.html : 유저 세부 사항
(해당 파일은 다 만들었다는 전제로 진행 / static 폴더는 형식상 생성 )
📗핵심 부분 정의
📃app.py
- write 함수
@app.route("/write")
def write():
if "uid" in session :
return render_template("write_post.html")
else :
return redirect(url_for("login"))
uid가 있는 상태(로그인)이면 write_post.html 파일은 렌더링 해준다.
그게 아닌 경우 login 페이지로 redirect 한다.
- write_done 함수
@app.route("/write_done",methods=["GET"])
def write_done():
title = request.args.get("title")
content = request.args.get("content")
uid = session.get("uid")
DB.write_post(uid=uid,content=content,title=title)
return redirect(url_for("index"))
write_post 페이지에 form 형태는 글 제목과 본문을 입력 받는다.
그리고 submit을 통해 write_done 함수에 title과 content 파라미터를 넘겨주고 호출한다.
그리고 session.get("uid")를 통해 uid 변수를 정의한다.
DB.write_post는 내가 정의한 객체로 위에 선언한 변수를을 파라미터로 넘겨주어 파이어 베이스에 저장.
(DB 클래스는 app.py 다음 설명)
- list 함수
@app.route("/list")
def post_list():
post_list = DB.post_list()
if post_list is None:
length = 0
else :
length = len(post_list)
return render_template("post_list.html",post_list=post_list.items(),length=length)
DB.write_list는 내가 정의한 객체로 글 목록 정보들을 반환해준다.
만일 포스팅 한 글이 하나도 없으면 length=0, 그게 아니면 post_list의 개수로 length 값을 할당해준다.
그리고 post_list.html 을 렌더링하고 변수 post_list, length를 각각 넘겨준다.
- post 함수
@app.route("/post/<string:pid>")
def post(pid) :
post = DB.post_detail(pid=pid)
return render_template("post_detail.html",post=post)
post_list.html에서는 모든 포스터들의 pid와 title을 보여주는데, 여기서 pid를 post_list로 전달한다.
정의한 DB.post_detail 함수에 pid 를 건네주어, 해당 pid와 일치하는 포스터의 items를 리턴하고 post에 저장한다.
그리고 post_detail.html에 렌더링하고 post 값을 파라미터 값으로 건네준다.
- user_post 함수
@app.route("/user/<string:uid>")
def user_post(uid) :
u_post = DB.get_user(uid)
if u_post is None :
length = 0
else :
length = len(u_post)
return render_template("user_detail.html",post_list=u_post,length=length,uid=uid)
현재 로그인 중인 유저가 쓴 글을 보여주는 함수이다.
정의한 DB.get_user에 uid를 넘겨주면, 해당 uid를 가지고 있는 모든 포스터들을 반환한다.
만약 반환된 포스터가 한개도 없으면 length = 0 을 주고, 그게 아니면 그 포스트 개수만큼 length 값을 할당한다.
그리고 user_detail.html을 렌더링하여 post_list, length, uid를 파라미터값으로 건네준다.
📃DB_handler.py
📕DBModule 클래스
...
def write_post(self,title,content,uid):
pid = str(uuid.uuid4())[:10]
informations = {
"title" : title,
"contents" : content,
"uid" : uid
}
self.db.child("posts").child(pid).set(informations)
def post_list(self):
post_list = self.db.child("posts").get().val()
return post_list
def post_detail(self,pid):
post = self.db.child("posts").get().val()[pid]
return post
def get_user(self,uid):
post_list = []
users_post = self.db.child("posts").get().val()
for post in users_post.items():
if post[1]["uid"] == uid :
post_list.append(post)
return post_list
(로그인/회원가입 관련 코드는 지난 포스팅에 작성했기 때문에 생략했다.)
- write_post 함수
중복되지 않은 값을 주기위해 uuid를 pid (포스터 id)로 주었다.
그리고 파라미터 title.content,uid를 informations에 넣어 firebase의 posts에 넣어주었다.
[데이터 베이스 posts 구조]
├─ POSTS─ PID
│ └─TITLE
│ CONTENT
│ UID
- post_list 함수
저장된 posts의 값들을 가져와 반환해준다.
- post_detail 함수
파라미터 pid에 해당하는 ITEMS들(TITLE,CONTENT,UID)을 반환해준다.
- get_user 함수
모든 포스터들을 다 가져와 users_post에 넣어준다.
그런 다음 각각 post들의 pid를 반복문으로 돌린다.
전달 받은 uid와 각각 post들의 uid가 일치하는 post를 post_list에 다 넣어준다. (해당 유저가 작성한 글 확인)
그리고 post_list 값들을 반환해준다.
📃 write_post.html
{%extends "base.html"%}
{% block contents %}
<form action="{{url_for('write_done')}}">
<input type="text" value="제목을 입력해주세요" name="title" id="title" required>
<input type="text" value="본문을 입력해주세요" name="content" id="content" required>
<button type="submit">작성하기 </button>
</form>
{% endblock contents %}
base.html의 기본 템플릿을 가져온다.
input 태그에 포스터의 제목과 내용을 입력받아 form을 통해 write_done에 전해준다.
📃 post_list.html
{%extends "base.html"%}
{% block contents %}
<h2>글 목록</h2>
{% if length == 0 %}
<p>{{user}}의 post </p>
{% else %}
{% for post in post_list %}
<a href="{{url_for('post',pid=post[0])}}">
<div>
{{post[0]}}
{{post[1]["title"]}}
</div>
</a>
{% endfor %}
{% endif %}
{% endblock contents %}
똑같이 base.html 템플릿을 가져오고,
if 문을 통해 length가 0일 경우와 0이 아닐 경우를 나눠준다.
그리고 전달 받은 post_list를 반복문으로 돌리고,
a 태그를 사용해서 post[0] (PID)를 post 함수로 전달하게 한다.
아래의 div 태그는 각각 포스터들의 PID와 ITEMS(TITLE)을 나타낸다.
📃 post_detail.html
{%extends "base.html"%}
{% block contents %}
<p>제목 : {{post["title"]}}</p>
<p>작성자 : {{post["uid"]}}</p>
<p>내용 : {{post["contents"]}}</p>
{% endblock contents %}
post_detail 페이지에서는 flask post 함수의 pid로 부터 추출한 post를 가져온다.
그리고 post의 ITEMS(TITLE,UID,CONTENTS)를 보여준다.
📃 user_detail.html
{%extends "base.html"%}
{% block contents %}
<h2>글 목록</h2>
{% if length == 0 %}
<p>작성된 포스트가 없습니다.</p>
{% else %}
{% for post in post_list %}
<a href="{{url_for('post',pid=post[0])}}">
<div>
{{post[0]}}
{{post[1]["title"]}}
</div>
</a>
{% endfor %}
{% endif %}
{% endblock contents %}
user_detail.html에서는 현재 로그인 사용자의 uid를 통해, 해당 uid와 일치하는 post들을 리턴값으로 준다.
리턴값으로 받은 post_list들은 반복문을 통해 주어지고,
a 태그를 통해 각각의 post들에 들어갈 수 있는 링크를 만들어준다.
div 태그는 a 태그안에 있어, 해당 post의 pid와 title을 나타낸다.
🧐 마무리
간단한 포스팅과 포스트 목록들을 구현해봤다.
session의 uid를 정의해서, uid와 직결된 url을 만드는 방법을 알아서 좋았다.
pid 또한 중복 될 수 없는 값으로 정의해주고, 각각 post들의 pid에 직결된 url을 만들었다.
flask / DB / HTML 파일들이 서로 유기적 관계를 이뤄 헷갈린다.
아직 익숙하지 않아서 그런것 같다.
하지만 나중에 유지보수에는 객체로 해서 훨씬 편할 것 같다.
📑참고 코드 파일
'WEB > Backend' 카테고리의 다른 글
[Firebase] 데이터베이스에 CSV 파일 Import (0) | 2024.05.21 |
---|---|
[Firebase] "error" : "Permission denied" 오류 (0) | 2024.05.20 |
[Python] Flask 로그인/회원가입 기능 만들기 (0) | 2024.04.12 |
[Python] Firebase 시작하기 (0) | 2024.04.08 |
Flask로 서버 배포하기 (AWS EC2) (0) | 2024.03.25 |