Flask - 팬명록

장현웅·2023년 8월 16일
0

EXAMPLE) Project 4. [팬명록]

1) Flask 폴더 구조 만들기

1) 프로젝트 폴더(fan) 생성
2) 프로젝트 폴더 안에 app.py 파일 생성
3) 가상환경(venv) 만들고 활성화
4) 패키지 설치 (flask, pymongo, dnspython, requests, bs4,)
pip install flask pymongo dnspython requests bs4(여러 개를 설치할 때는 띄어쓰기로 구분)
5) templates 폴더 생성 하고 index.html 파일 생성

fan 폴더 구조
- - -
fan 
|— venv
|— app.py (서버)
|— templates
         |— index.html (클라이언트 파일)

2) 서버(app.py)

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

from pymongo import MongoClient

client = MongoClient('mongodb+srv://sparta:test@cluster0.wop0dox.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta

@app.route('/')
def home():
   return render_template('index.html')

@app.route("/guestbook", methods=["POST"])
def guestbook_post():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'POST 연결 완료!'})

@app.route("/guestbook", methods=["GET"])
def guestbook_get():
    return jsonify({'msg': 'GET 연결 완료!'})

if __name__ == '__main__':
   app.run('0.0.0.0', port=5000, debug=True)

3) 클라이언트(index.html) script 함수부분

$(document).ready(function () {
  set_temp();
  show_comment();
 });
 
function set_temp() {
 fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then((res) => res.json()).then((data) => {
	console.log(data)
    });
}
function save_comment() {
  let formData = new FormData();
  formData.append("sample_give", "샘플데이터");

  fetch('/guestbook', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
      //console.log(data)
      alert(data["msg"]);
    });
}
function show_comment() {
  fetch('/guestbook').then((res) => res.json()).then((data) => {
	alert(data["msg"])
	})
}
<div class="mycards" id="comment-list">
      <div class="card">
        <div class="card-body">
          <blockquote class="blockquote mb-0">
            <p>새로운 앨범 너무 멋져요!</p>
            <footer class="blockquote-footer">호빵맨</footer>
          </blockquote>
        </div>
      </div>

4. 프로젝트 준비 - mongoDB Atlas 창 띄워두기

5. app.py 터미널에서 실행해보고 브라우저 localhost:5000 들어가보기

$(document).ready(function () {
  set_temp();
  show_comment();
});

→ 문서가 준비되면 set_temp()함수와 show_comment()함수가 불려온다.

function set_temp() {
  fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then((res) => res.json()).then((data) => {
	console.log(data)
  });
}

function show_comment() {
 fetch('/guestbook').then((res) => res.json()).then((data) => {
	alert(data["msg"])
	})
}
@app.route("/guestbook", methods=["GET"])
def guestbook_get():
    return jsonify({'msg': 'GET 연결 완료!'})

→ set_temp() : 이미 db가 구축된 서버인 OpenAPI에서 데이터를 가져오기만 하면 됨. 페이지에 보여주려면 받아온 데이터를 temp_html에 담아서 제이쿼리로 append해주면 된다.

→ API /guestbook에서 데이터를 가져와서 데이터를 json형식으로 내려준다. (우리는 데이터를 json형식으로 가져와서 GET으로 읽는 것이다.)

→ fetch를 통해서 서버가 API /guestbook에서 받아온 데이터를 가져와서 alert로 띄운다.
}

function save_comment() {
  let formData = new FormData();
  formData.append("sample_give", "샘플데이터");

  fetch('/guestbook', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
     //console.log(data)
     alert(data["msg"]);
  });
}
@app.route("/guestbook", methods=["POST"])
def guestbook_post():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'POST 연결 완료!'})

→ save_comment() : '댓글 남기기' 버튼을 누르면 FormData에 "샘플데이터"의 형태로 데이터를 담아준 후 서버로 보내줌.

→ 서버는 클라이언트로부터 'sample_give'라는 데이터를 받아와서 프린트하고 클라이언트로 데이터를 msg('POST 연결 완료!) 형태로 내려준다.

→ 클라이언트는 fetch로 서버로부터 내려온 데이터의 메시지부분을 alert로 띄우고 새로고침(API /bucket에 갱신된 모든 데이터를 받아와서 출력) 한다.

6. [팬명록] - 조각기능. 날씨 API 적용하기

{
city: "Seoul",
clouds: "75%",
icon: "http://openweathermap.org/img/w/04d.png",
temp: 31.15
}

→ 필요한 값은 temp값
→ fetch로 서울 날씨 OpenAPI에서 데이터를 json형식으로 가져와서 temp 값만 따로 담은 리스트를 하나의 변수 값으로 지정하고 jQuery를 이용하여 text형식으로 원하는 부분에 출력한다.

    <div class="mypic">
      <h1>십센치(10cm) 팬명록</h1>
      <p>현재기온: <span id="temp">36</span></p>
    </div>

→ id="temp"에 붙여준다.

function set_temp() {
fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then((res) => res.json()).then((data) => {
    let temp = data['temp']
    $("#temp").text(temp)
  })

→ 동작 테스트

7. [팬명록] - POST 연습하기(API 만들고 사용하기 - 응원 게시하기 API(Create→POST))

  • 1) 데이터명세 (데이터 생성은 POST)

    • 1.요청정보 : URL = /guestbook, 요청방식 = POST
    • 2.클라(fetch) → 서버(flask) : name, comment
    • 3.서버(flask) → 클라(fetch) : 메시지를 보냄 (응원 완료!)
  • 2) 서버(app.py)

2-1) 데이터베이스에 연결

from pymongo import MongoClient

client = MongoClient('mongodb+srv://sparta:test@cluster0.wop0dox.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta

2-2) 클라이언트로부터 name, comment 정보(name_give, comment_give)를 받아서, 저장(name_receive, comment_receive)

@app.route("/guestbook", methods=["POST"])
def guestbook_post():
    name_receive = request.form["name_give"]
    comment_receive = request.form["comment_give"]

    doc = {
        'name': name_receive,
        'comment': comment_receive
    }

    db.fan.insert_one(doc)
    return jsonify({'msg':'응원 완료!'})
  • 3) 클라이언트(index.html)
function save_comment() {
        let name = $("#name").val();
        let comment = $("#comment").val(); # name, comment 정보를

        let formData = new FormData();
        formData.append("name_give", name);
        formData.append("comment_give", comment); # formData에 데이터를 넣고

        fetch('/guestbook', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => { # API /guestbook으로 보내주고
            alert(data["msg"]); # 서버에서 내려준 메시지 데이터를 alert로 띄움.
            window.location.reload(); # 저장되면, 새로고침을 해서 다시 보여줄 준비
          });
      }
  • 4) 완성 확인

8. [팬명록] - GET 연습하기(API 만들고 사용하기 - 버킷리스트 조회 API(Read→GET))

  • 1) 데이터 명세 (데이터 조회는 GET)
      1. 요청 정보 : URL= /guestbook, 요청 방식 = GET
      1. 클라(fetch) → 서버(flask) : 없음
      1. 서버(flask) → 클라(fetch) : 전체 응원 목록을 보여주기
  • 2) 서버(app.py)
@app.route("/guestbook", methods=["GET"])
def guestbook_get():
    all_comments = list(db.fan.find({},{'_id':False}))
    return jsonify({'result':all_comments})

# 받을 것 없이 fan 에 name, comment를 담아서 내려주기만 하면 됨.
  • 3) 클라이언트(index.html)
function show_comment() {
        fetch('/guestbook').then((res) => res.json()).then((data) => {
            let rows = data['result']
		        $("#comment-list").empty() # 기존 html 코드들을 지워줄 수 있도록 empty()
            rows.forEach((a) => { # 응원 목록(리스트)을 forEach문으로 반복하면서 데이터를 뽑아냄.
              let name = a['name']
              let comment = a['comment']

              let temp_html = `<div class="card">
                            <div class="card-body">
                                <blockquote class="blockquote mb-0">
                                    <p>${comment}</p>
                                    <footer class="blockquote-footer">${name}</footer>
                                </blockquote>
                            </div>
                        </div>`
              $("#comment-list").append(temp_html) # 가져온 데이터를 temp_html로 뼈대에 데이터를 담아 제이쿼리로 append
            })
          })
      }
  • 4) 완성 확인
서버(app.py)

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

from pymongo import MongoClient

client = MongoClient('내 mongodb URL')
db = client.dbsparta

@app.route('/')
def home():
   return render_template('index.html')

@app.route("/guestbook", methods=["POST"])
def guestbook_post():
    name_receive = request.form["name_give"]
    comment_receive = request.form["comment_give"]

    doc = {
        'name': name_receive,
        'comment': comment_receive
    }

    db.fan.insert_one(doc)
    return jsonify({'msg':'응원 완료!'})

@app.route("/guestbook", methods=["GET"])
def guestbook_get():
    all_comments = list(db.fan.find({},{'_id':False}))
    return jsonify({'result':all_comments})

if __name__ == '__main__':
   app.run('0.0.0.0', port=5000, debug=True)
클라이언트(index.html)

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />

    <link
      href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
      rel="stylesheet"
      integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
      crossorigin="anonymous"
    />
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script
      src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js"
      integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
      crossorigin="anonymous"
    ></script>

    <title>초미니홈피 - 팬명록</title>

    <link
      href="https://fonts.googleapis.com/css2?family=Noto+Serif+KR:wght@200;300;400;500;600;700;900&display=swap"
      rel="stylesheet"
    />
    <style>
      * {
        font-family: "Noto Serif KR", serif;
      }
      .mypic {
        width: 100%;
        height: 300px;

        background-image: linear-gradient(
            0deg,
            rgba(0, 0, 0, 0.5),
            rgba(0, 0, 0, 0.5)
          ),
          url("https://cdn.topstarnews.net/news/photo/201807/456143_108614_510.jpg");
        background-position: center 30%;
        background-size: cover;

        color: white;

        display: flex;
        flex-direction: column;
        align-items: center;
        justify-content: center;
      }

      .mypost {
        width: 95%;
        max-width: 500px;
        margin: 20px auto 20px auto;

        box-shadow: 0px 0px 3px 0px black;
        padding: 20px;
      }

      .mypost > button {
        margin-top: 15px;
      }

      .mycards {
        width: 95%;
        max-width: 500px;
        margin: auto;
      }

      .mycards > .card {
        margin-top: 10px;
        margin-bottom: 10px;
      }
    </style>
    <script>
      $(document).ready(function () {
        set_temp();
        show_comment();
      });
      function set_temp() {
        fetch("http://spartacodingclub.shop/sparta_api/weather/seoul").then((res) => res.json()).then((data) => {
        let temp = data['temp']
        $("#temp").text(temp)
      })
    }
      function save_comment() {
        let name = $("#name").val();
        let comment = $("#comment").val();

        let formData = new FormData();
        formData.append("name_give", name);
        formData.append("comment_give", comment);

        fetch('/guestbook', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
            alert(data["msg"]);
            window.location.reload();
          });
      }
      function show_comment() {
        fetch('/guestbook').then((res) => res.json()).then((data) => {
            let rows = data['result']
		        $("#comment-list").empty()
            rows.forEach((a) => {
              let name = a['name']
              let comment = a['comment']

              let temp_html = `<div class="card">
                            <div class="card-body">
                                <blockquote class="blockquote mb-0">
                                    <p>${comment}</p>
                                    <footer class="blockquote-footer">${name}</footer>
                                </blockquote>
                            </div>
                        </div>`
              $("#comment-list").append(temp_html)
            })
          })
      }
    </script>
  </head>
  <body>
    <div class="mypic">
      <h1>십센치(10cm) 팬명록</h1>
      <p>현재기온: <span id="temp">36</span></p>
    </div>
    <div class="mypost">
      <div class="form-floating mb-3">
        <input type="text" class="form-control" id="name" placeholder="url" />
        <label for="floatingInput">닉네임</label>
      </div>
      <div class="form-floating">
        <textarea
          class="form-control"
          placeholder="Leave a comment here"
          id="comment"
          style="height: 100px"
        ></textarea>
        <label for="floatingTextarea2">응원댓글</label>
      </div>
      <button onclick="save_comment()" type="button" class="btn btn-dark">
        댓글 남기기
      </button>
    </div>
    <div class="mycards" id="comment-list">
      <div class="card">
        <div class="card-body">
          <blockquote class="blockquote mb-0">
            <p>새로운 앨범 너무 멋져요!</p>
            <footer class="blockquote-footer">호빵맨</footer>
          </blockquote>
        </div>
      </div>
      <div class="card">
        <div class="card-body">
          <blockquote class="blockquote mb-0">
            <p>새로운 앨범 너무 멋져요!</p>
            <footer class="blockquote-footer">호빵맨</footer>
          </blockquote>
        </div>
      </div>
      <div class="card">
        <div class="card-body">
          <blockquote class="blockquote mb-0">
            <p>새로운 앨범 너무 멋져요!</p>
            <footer class="blockquote-footer">호빵맨</footer>
          </blockquote>
        </div>
      </div>
    </div>
  </body>
</html>

9. og태그 넣기

<meta property="og:title" content="내 사이트의 제목" />
<meta property="og:description" content="보고 있는 페이지의 내용 요약" />
<meta property="og:image" content="이미지URL" />

→ title 밑에 붙여줌.

<title>초미니홈피 - 팬명록</title>

  <meta property="og:title" content="싸이 팬명록" />
  <meta property="og:description" content="아티스트에게 응원 한마디" />
  <meta property="og:image" content="https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS7gal0XRHqQnae8yU5QPpoxvoXdD9p-eZ6kQ&usqp=CAU" />

→ 백그라운드 이미지도 변경

.mypic {
      width: 100%;
      height: 300px;

      background-image: linear-gradient(0deg,
          rgba(0, 0, 0, 0.5),
          rgba(0, 0, 0, 0.5)),
        url("https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS7gal0XRHqQnae8yU5QPpoxvoXdD9p-eZ6kQ&usqp=CAU");

0개의 댓글