본문 바로가기
항해99/프로젝트

[Flask] 버킷리스트 프로젝트(서버, DB)

by junvely 2023. 2. 15.

🦄 버킷리스트 프로젝트(서버, DB)

사용자가 버킷리스트 데이터를 입력하면 DB에 저장하고, Window가 reload되면 DB에서 버킷리스트들을 가져와서 화면에 보여주는 간단한 프로젝트이다.

강의에서 진행한 DB에 추가, 가져오기 기능 외에도 버튼 클릭 시 완료(done)여부를 수정할 수 있는 기능도 추가해 보고 싶어서 혼자 한번 추가하여 진행해 봤다! 다음과 같은 flow로 진행 된다.

'완료' 버튼 클릭 => DB에서 text를 받아 done 여부를 확인 => T 또는 F 로 데이터를 수정

=> window를 reload => DB의 변경된 정보로 다시 리스트 가져옴 => done의 T와 F에 따라 버튼 디자인을 다르게 적용


 

03 버킷리스트 - 프로젝트 셋팅

- 서버, DB만 사용 => Flask, pymongo, dnspython 설치

pip install flask pymongo dnspython

 

04 버킷리스트 - 뼈대 준비하기

- Flask, 크롤링, DB 연결

# 서버
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

# requests,bs4
import requests
from bs4 import BeautifulSoup
headers = {'User-Agent' : 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)AppleWebKit/537.36 (KHTML, like Gecko) Chrome/73.0.3683.86 Safari/537.36'}
data = requests.get('https://movie.naver.com/movie/sdb/rank/rmovie.naver?sel=pnt&date=20210829',headers=headers)
soup = BeautifulSoup(data.text, 'html.parser')

# db => <password>꼭 바꿔주기
from pymongo import MongoClient
client = MongoClient('mongodb+srv://junvely:test@cluster0.38f4se1.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta

 

05 버킷리스트 - POST API 만들기

1. 백엔드 POST API 

- 받을 정보 : 텍스트 입력값  => DB에 저장

@app.route("/bucket", methods=["POST"])
def bucket_post():
    text_receive = request.form['text_give']

    doc = {
        'text' : text_receive,
        'success' : False,
    }

    db.buckets.insert_one(doc)
    return jsonify({'msg': '기록 완료!'})

2. 프론트 POST API

- index.html

function save_bucket() {
        let text = $("#bucket").val();

        let formData = new FormData();
        formData.append("text_give", text);

        fetch("/bucket", { method: "POST", body: formData })
          .then((response) => response.json())
          .then((data) => {
            alert(data["msg"]);
            window.location.reload();
          });
      }

 

06 버킷리스트 - GET API 만들기

1. 백엔드 GET API 

- 받을 정보 : 텍스트 입력값  => DB에 저장

@app.route("/bucket", methods=["GET"])
def bucket_get():
    buckets = list(db.buckets.find({},{"_id":False}))
    return jsonify({'buckets': buckets})

2. 프론트 GET API

- index.html

function show_bucket() {
        fetch("/bucket")
          .then((res) => res.json())
          .then((data) => {
            let buckets = data["buckets"];
            buckets.forEach((bucket) => {
              let text = bucket["text"];
              let success = bucket["success"];

              let temp_html = `
                                <li>
                                    <h2>✅ ${text}</h2>
                                    <button
                                      onclick="done_bucket(5)"
                                      type="button"
                                      class="btn btn-outline-primary"
                                    >
                                      완료!
                                    </button>
                                </li>
                              `;
              $("#bucket-list").append(temp_html);
            });
          });
      }

 

07 버킷리스트 - 완료(done)기능 추가하기(POST)

- '완료' 버튼을 클릭하면, DB에서 done 여부를 확인하여 T 또는 F 로 데이터를 수정해 주는 기능을 추가하여 구현해 보았다.

- 버튼 클릭 => DB에서 done 여부를 확인하여 T 또는 F 로 데이터를 수정

=> window를 reload => DB의 변경된 정보로 다시 리스트 가져옴 => done의 T와 F에 따라 버튼 디자인을 다르게 적용

 

1. 백엔드 POST API

# 함수이름 중복 주의
def bucket_done_post(): 
    text_receive = request.form['text_give']
    # 받아온 text에서 공백+⭐를 제거한 text를 찾기위한 코드 텍스트의 2번째부터~ 가져오기
    text = text_receive[2:]

    done = db.buckets.find_one({'text': text})['done']
    
    if done == True :
        db.buckets.update_one({'text':text},{'$set':{'done': False}}) # T > F
    else :
        db.buckets.update_one({'text':text},{'$set':{'done': True}}) # F > T

    return jsonify({'msg': '성공!'})

함수 이름을 bucket_post로 했다가 중복 에러가 났다..주의!

 

2. 프론트 POST 요청

function show_bucket() {
        fetch("/bucket")
          .then((res) => res.json())
          .then((data) => {
            let buckets = data["buckets"];
            buckets.forEach((bucket) => {
              let text = bucket["text"];
              let done = bucket["done"];

              let temp_html = ``;
              
              // done이 true일 경우, false일 경우 버튼 스타일 다르게 적용
              if (done === true) {
                temp_html = `
                                <li>
                                  <h2 class="done">⭐ ${text}</h2>
                                    <button
                                      onclick="done_bucket(event)"
                                      type="button"
                                      class="btn btn-outline-primary success"
                                    >
                                      완료
                                    </button>
                                </li>
                            `;
              } else {
                temp_html = `
                                <li>
                                  <h2>⭐ ${text}</h2>
                                    <button
                                      onclick="done_bucket(event)"
                                      type="button"
                                      class="btn btn-outline-success"
                                    >
                                      완료
                                    </button>
                                </li>

                             `;
              }

              $("#bucket-list").append(temp_html);
            });
          });
      }

// 버튼 클릭 시 마다 done여부 수정하기 위해 text 보내줌
function done_bucket(event) {
		// event.target(버튼)의 부모(h2) text가져옴
        let target = $(event.target).prev();
        let targetText = target.text();

        let formData = new FormData();
        formData.append("text_give", targetText);

        fetch("bucket-done", { method: "POST", body: formData })
          .then((res) => res.json())
          .then((data) => {
            window.location.reload();
          });
      }

- 버튼 클릭 시, done여부 수정을 위해 event.target인 버튼의 => 형제노드인 h2의 텍스트를 가져온다.

- window가 reload되면 => DB의 변경된 정보로 다시 리스트 가져오는데

=> 이 때 done의 T와 F에 따라 버튼 디자인을 다르게 적용

- 완성!!🙌