[웹 개발] 4주차 : Flask 프레임워크를 활용해 API 만들기, POST, GET

hyeonbin·2023년 2월 3일

웹 개발

목록 보기
7/9
post-thumbnail

📢 시작 한마디

늘어지지 말고, 정신 똑바로 챙겨서 공부하자!

방심은 금물이지, 끝날 때까지 끝난 게 아니다! 👍👍


✅ 4주차 진행 및 완료 사항

  • Flask 프레임워크를 활용해서 API 만들기
  • '화성에 땅사기' API 만들고 클라이언트에 연결
  • '스파르타피디아' API 만들고 클라이언트와 연결
  • 4주차 숙제 : 팬명록 완성하기 (POST, GET)


✅ 오늘 배운 내용

projects 폴더 아래,
bucket, homework, mars, movie, prac 5개 폴더 만들고 시작!

📍 Flask 시작하기 - 서버 만들기

  1. new project → prac 폴더 선택 후, create 클릭

  2. Flask 패키지 설치

   윈도우 : 좌상단 File → setting → python interpreter
   
   + 버튼 눌러 flask 검색한 후, 패키지 설치
  1. Flask 기초 : 기본 실행
   Flask 프레임워크? 
   
   서버를 구동시켜주는 편한 코드 모음
   서버를 구동하려면 필요한 복잡한 일들을 쉽게 가져다 사용 가능
  • app.py 파일 만들어 flask 시작 코드 붙여넣기
   from flask import Flask
   app = Flask(__name__)

   @app.route('/')
   def home():
   return 'This is Home!'

   if __name__ == '__main__':  
   app.run('0.0.0.0',port=5000,debug=True)
  • 실행 누르고, 터미널에 아래와 같은 메시지 뜨면 실행 성공!

  • 크롬에서 http://localhost:5000/ 접속

    → 화면에 'This is Home'이라는 메시지 보이면 성공
    → 종료 방법 : 터미널 창 클릭, ctrl + c 누르면 서버 종료

  1. Flask 기초 : URL 나눠보기
  • @app.route('/) 부분을 수정해서 URL 나누기

    url 별로 함수명이 같거나, route('/') 내의 주소가 같으면 X

   from flask import Flask
   app = Flask(__name__)
   
   @app.route('/')
   def home():
   return 'This is Home!'
   
   @app.route('/mypage')
   def mypage():  
   return 'This is My Page!'

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


📍 Flask 시작하기 - HTML 파일 주기

  1. Flask 기초 : 기본 폴더 구조
   Flask 서버를 만들 때!
  
   프로젝트 폴더 안에,
  
   ㄴstatic 폴더 (이미지, css파일을 넣어둠)
   ㄴtemplates 폴더 (html파일을 넣어둠)
   ㄴapp.py 파일
  
   이렇게 3개를 만들어두고 시작!

  1. Flask 기초 : HTML 파일 불러오기
  • templates 안에 index.html 파일 만들기

  • HTML 파일 불러오기

    → Flask 내장함수 render_template 이용 (이게 바로 프레임워크의 위력!)



📍 Flask 시작하기 - 본격 API 만들기

  1. 들어가기 전에 : GET, POST 요청타입 리마인드
  • 리마인드
   은행의 창구가 API와 같다는 것!
   같은 예금 창구에서도 개인 고객이냐 기업 고객이냐에 따라 처리하는 것이 다른 것처럼,
   클라이언트가 요청 할 때에도, "방식"이 존재
   
   HTTP 라는 통신 규약을 따른다는 거 잊지말기! 
   클라이언트는 요청할 때 HTTP request method(요청 메소드)를 통해, 
   어떤 요청 종류인지 응답하는 서버 쪽에 정보를 알려주는 것

  • GET, POST 방식
   여러 방식[링크](https://developer.mozilla.org/ko/docs/Web/HTTP/Methods)이 존재

   * GET  →  통상적으로! 데이터 조회(Read)를 요청할 때
             예) 영화 목록 조회
             
          →  데이터 전달 : URL 뒤에 물음표를 붙여 key=value로 전달
             예) google.com?q=북극곰

   * POST  →  통상적으로! 데이터 생성(Create), 변경(Update), 삭제(Delete) 요청 할 때
              예) 회원가입, 회원탈퇴, 비밀번호 수정
              
           →  데이터 전달 : 바로 보이지 않는 HTML body에 key:value 형태로 전달

  1. GET, POST 요청에서 클라이언트의 데이터를 받는 방법
  • jquery 임포트 - index.html
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>

  • GET 요청 확인 Ajax 코드 - index.html
   $.ajax({
       type: "GET",
       url: "/test?title_give=봄날은간다",
       data: {},
       success: function(response){
           console.log(response)
       }
   })
  • request, jsonify 임포트 - app.py
   from flask import Flask, render_template, request, jsonify
  • GET 요청 API 코드 - app.py
   @app.route('/test', methods=['GET'])
   def test_get():
  	  title_receive = request.args.get('title_give')
   	  print(title_receive)
   	  return jsonify({'result':'success', 'msg': '이 요청은 GET!'})
      
   # title_give를 받아와서, title_receive 변수에 넣고, 걔를 찍어준다
   # /test라는 창구에서 그것을 받고 있다
  • POST 요청 확인 Ajax 코드 - index.html
   $.ajax({
       type: "POST",
       url: "/test",
       data: { title_give:'봄날은간다' },
       success: function(response){
           console.log(response)
       }
   })
  • POST 요청 API 코드 - app.py
   @app.route('/test', methods=['POST'])
   def test_post():
      title_receive = request.form['title_give']
      print(title_receive)
      return jsonify({'result':'success', 'msg': '이 요청은 POST!'})
      
   # /test라는 창구를 만들었고, POST만 받는 것은 이쪽 창구로 와라 
   # title_give를 받아와서, 변수에 넣고 찍어준다


📍 화성땅 공동구매 - 프로젝트 세팅

  1. new project → mars 폴더 선택 후, create 클릭

  2. 폴더 구조 잡기

   1) 파일 → 새로 작성 → 디렉토리 → templates, static 파일 만들기
   2) templates 폴더 안에 index.html 파일 만들기
   3) app.py 파일 만들기
  1. 패키지 설치
   윈도우 : 좌상단 File → setting → python interpreter
   
   + 버튼 눌러 flask, pymongo, dnspython 3개 패키지 설치


📍 화성땅 공동구매 - 뼈대 준비하기

  1. 프로젝트 준비 - app.py
   from flask import Flask, render_template, request, jsonify
   app = Flask(__name__)

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

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

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

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

  1. 프로젝트 준비 - 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>

    <link href="https://fonts.googleapis.com/css2?family=Gowun+Batang:wght@400;700&display=swap" rel="stylesheet">

    <title>선착순 공동구매</title>

    <style>
        * {
            font-family: 'Gowun Batang', serif;
            color: white;
        }

        body {
            background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://cdn.aitimes.com/news/photo/202010/132592_129694_3139.jpg');
            background-position: center;
            background-size: cover;
        }

        h1 {
            font-weight: bold;
        }

        .order {
            width: 500px;
            margin: 60px auto 0px auto;
            padding-bottom: 60px;
        }

        .mybtn {
            width: 100%;
        }

        .order > table {
            margin : 40px 0;
            font-size: 18px;
        }

        option {
            color: black;
        }
    </style>
    <script>
        $(document).ready(function () {
            show_order();
        });
        function show_order() {
            $.ajax({
                type: 'GET',
                url: '/mars',
                data: {},
                success: function (response) {
                    alert(response['msg'])
                }
            });
        }
        function save_order() {
            $.ajax({
                type: 'POST',
                url: '/mars',
                data: { sample_give:'데이터전송' },
                success: function (response) {
                    alert(response['msg'])
                }
            });
        }
    </script>
</head>
<body>
    <div class="mask"></div>
    <div class="order">
        <h1>화성에 땅 사놓기!</h1>
        <h3>가격: 평 당 500원</h3>
        <p>
            화성에 땅을 사둘 수 있다고?<br/>
            앞으로 백년 간 오지 않을 기회. 화성에서 즐기는 노후!
        </p>
        <div class="order-info">
            <div class="input-group mb-3">
                <span class="input-group-text">이름</span>
                <input id="name" type="text" class="form-control">
            </div>
            <div class="input-group mb-3">
                <span class="input-group-text">주소</span>
                <input id="address" type="text" class="form-control">
            </div>
            <div class="input-group mb-3">
                <label class="input-group-text" for="size">평수</label>
                <select class="form-select" id="size">
                  <option selected>-- 주문 평수 --</option>
                  <option value="10평">10평</option>
                  <option value="20평">20평</option>
                  <option value="30평">30평</option>
                  <option value="40평">40평</option>
                  <option value="50평">50평</option>
                </select>
              </div>
              <button onclick="save_order()" type="button" class="btn btn-warning mybtn">주문하기</button>
        </div>
        <table class="table">
            <thead>
              <tr>
                <th scope="col">이름</th>
                <th scope="col">주소</th>
                <th scope="col">평수</th>
              </tr>
            </thead>
            <tbody>
              <tr>
                <td>홍길동</td>
                <td>서울시 용산구</td>
                <td>20평</td>
              </tr>
              <tr>
                <td>임꺽정</td>
                <td>부산시 동구</td>
                <td>10평</td>
              </tr>
              <tr>
                <td>세종대왕</td>
                <td>세종시 대왕구</td>
                <td>30평</td>
              </tr>
            </tbody>
          </table>
    </div>
</body>
</html>

  1. 프로젝트 준비 - mongoDB Atlas
   https://cloud.mongodb.com/


📍 화성땅 공동구매 - POST 연습 (주문 저장)

  1. API 만들고 사용하기 - 이름, 주소, 평수 저장하기 (Create → POST)
   1) 요청 정보 :  URL= /mars, 요청 방식 = POST
   2) 클라(ajax) → 서버(flask) : name, address, size
   3) 서버(flask) → 클라(ajax) : 메시지를 보냄(주문 완료!)

  1. 클라이언트와 서버 연결 확인하기
  • 서버 코드 - app.py
   @app.route("/mars", methods=["POST"])
   def web_mars_post():
       sample_receive = request.form['sample_give']
       print(sample_receive)
       return jsonify({'msg': 'POST 연결 완료!'})
  • 클라이언트 코드 - index.html
   function save_order() {
       $.ajax({
           type: 'POST',
           url: '/mars',
           data: { sample_give:'데이터전송' },
           success: function (response) {
               alert(response['msg'])
           }
       });
   }

   <button onclick="save_order()" type="button" class="btn btn-warning mybtn">주문하기</button>

  1. 서버부터 만들기
  • name, address, size 정보를 받아서 저장
  • 일전에 만들어둔 dbprac.py 파일을 불러와서 만들기 insert_one
   @app.route("/mars", methods=["POST"])
   def web_mars_post():
       name_receive = request.form['name_give']
       address_receive = request.form['address_give']
       size_receive = request.form['size_give']

       doc = {
           'name': name_receive,
           'address': address_receive,
           'size': size_receive
     }

     db.mars.insert_one(doc)

     return jsonify({'msg': '주문 완료!'})

  1. 클라이언트 만들기
  • 이번엔 name, address, size 정보를 보내주기
   function save_order() {
       let name = $('#name').val()
       let address = $('#address').val()
       let size = $('#size').val()

       $.ajax({
           type: 'POST',
           url: '/mars',
           data: { name_give:name, address_give:address, size_give:size },
           success: function (response) {
               alert(response['msg'])
               window.location.reload()
           }
       });
   }

  1. 완성 확인하기
  • DB에 잘 들어갔는지 확인

  1. 정리
   index.html
   1) 주문하기 버튼을 누르면 save_order()가 실행되고,
   2) name, address, size를 jquery로 가져와서,
   3) 데이터를 실어보냄(name_give, address_give, size_give)
   
   app.py
   4) 실어보내면 그 창구에서 약속한대로 받아다가 DB에다 저장하고,
   5) 그 다음 '주문 완료!'라고 다시 내려주면,
   
   index.html
   6) 데이터(name_give, address_give, size_give)가 그걸 받아서(response),
   7) 메시지만 alert로 보여주고 reload 함


📍 화성땅 공동구매 - GET 연습 (주문 보여주기)

  1. API 만들고 사용하기 - 저장된 주문을 화면에 보여주기 (Read → GET)
   1) 요청 정보 :  URL= /mars, 요청 방식 = GET
   2) 클라(ajax) → 서버(flask) : (없음)
   3) 서버(flask) → 클라(ajax) : 전체 주문을 보내주기

  1. 클라이언트와 서버 확인하기
  • 서버 코드 - app.py
   @app.route("/mars", methods=["GET"])
   def web_mars_get():
       return jsonify({'msg': 'GET 연결 완료!'})
  • 클라이언트 코드 - index.html
   $(document).ready(function () {
       show_order();
   });
   function show_order() {
       $.ajax({
           type: 'GET',
           url: '/mars',
           data: {},
           success: function (response) {
               alert(response['msg'])
           }
       });
   }

  1. 서버부터 만들기
  • 받을 것 없이 orders에 주문정보를 담아서 내려주기만 하면 됨!
  • 일전에 만들어둔 dbprac.py 파일을 불러와서 만들기
   @app.route("/mars", methods=["GET"])
   def web_mars_get():
       orders_list = list(db.mars.find({},{'_id':False}))
       return jsonify({'orders':orders_list})

  1. 클라이언트 만들기
  • 응답을 잘 받아서 for문으로 붙여주면 끝!
  • tbodyid값 넣고 temp_html을 붙여주기
   function show_order() {
       $('#order-box').empty()
       $.ajax({
           type: 'GET',
           url: '/mars',
           data: {},
           success: function (response) {
               let rows = response['orders']
               for (let i = 0; i < rows.length; i++) {
                   let name = rows[i]['name']
                   let address = rows[i]['address']
                   let size = rows[i]['size']

                   let temp_html = `<tr>
                                       <td>${name}</td>
                                       <td>${address}</td>
                                       <td>${size}</td>
                                     </tr>`
                    $('#order-box').append(temp_html)
               }

           }
       });
   }

  1. 완성 확인하기
  • 동작 테스트 : 화면을 새로고침 했을 때, DB에 저장된 리뷰가 화면에 올바르게 나타나는지 확인


  1. 정리
   app.py
   1) DB에서 모든 주문 갖고와서 orders라는 키로 orders_list 받아감
   
   index.html
   2) 클라이언트는 가져갈 거 없음
   3) response 콘솔 창에 찍어보면 orders가 들어있음
   4) 하나밖에 없으니 test2로 하나 더 넣고, 
   5) 응답 받아서 for문 돌려주고, 한 번 더 잘 나오는지 콘솔에 찍어보기
   6) 그 다음 화면 아래에 붙여줘야 하니까, temp_html을 tbody에 id 값 줘서 붙여주기
   7) 화면에 이름, 주소, 평수 넣고 잘 붙는지 확인!

  1. 전체 완성 코드
  • app.py
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)

from pymongo import MongoClient
client = MongoClient('mongodb+srv://test:sparta@cluster0.61uxirc.mongodb.net/Cluster0?retryWrites=true&w=majority')
db = client.dbsparta

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

@app.route("/mars", methods=["POST"])
def web_mars_post():
    name_receive = request.form['name_give']
    address_receive = request.form['address_give']
    size_receive = request.form['size_give']

    doc = {
        'name' : name_receive,
        'address' : address_receive,
        'size' : size_receive
    }
    db.mars.insert_one(doc)

    return jsonify({'msg': '주문 완료!'})

@app.route("/mars", methods=["GET"])
def web_mars_get():
    orders_list = list(db.mars.find({}, {'_id': False}))
    return jsonify({'orders': orders_list})

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>

    <link href="https://fonts.googleapis.com/css2?family=Gowun+Batang:wght@400;700&display=swap" rel="stylesheet">

    <title>선착순 공동구매</title>

    <style>
        * {
            font-family: 'Gowun Batang', serif;
            color: white;
        }

        body {
            background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://cdn.aitimes.com/news/photo/202010/132592_129694_3139.jpg');
            background-position: center;
            background-size: cover;
        }

        h1 {
            font-weight: bold;
        }

        .order {
            width: 500px;
            margin: 60px auto 0px auto;
            padding-bottom: 60px;
        }

        .mybtn {
            width: 100%;
        }

        .order > table {
            margin: 40px 0;
            font-size: 18px;
        }

        option {
            color: black;
        }
    </style>
    <script>
        $(document).ready(function () {
            show_order();
        });

        function show_order() {
            $.ajax({
                type: 'GET',
                url: '/mars',
                data: {},
                success: function (response) {
                    let rows = response['orders']
                    for (let i=0; i<rows.length; i++) {
                        let name = rows[i]['name']
                        let address = rows[i]['address']
                        let size = rows[i]['size']

                        let temp_html = `<tr>
                                            <td>${name}</td>
                                            <td>${address}</td>
                                            <td>${size}</td>
                                        </tr>`
                        $('#order-box').append(temp_html)
                    }
                }
            });
        }

        function save_order() {
            let name = $('#name').val()
            let address = $('#address').val()
            let size = $('#size').val()

            $.ajax({
                type: 'POST',
                url: '/mars',
                data: {name_give: name, address_give: address, size_give: size},
                success: function (response) {
                    alert(response['msg'])
                    window.location.reload()
                }
            });
        }
    </script>
</head>
<body>
<div class="mask"></div>
<div class="order">
    <h1>화성에 땅 사놓기!</h1>
    <h3>가격: 평 당 500원</h3>
    <p>
        화성에 땅을 사둘 수 있다고?<br/>
        앞으로 백년 간 오지 않을 기회. 화성에서 즐기는 노후!
    </p>
    <div class="order-info">
        <div class="input-group mb-3">
            <span class="input-group-text">이름</span>
            <input id="name" type="text" class="form-control">
        </div>
        <div class="input-group mb-3">
            <span class="input-group-text">주소</span>
            <input id="address" type="text" class="form-control">
        </div>
        <div class="input-group mb-3">
            <label class="input-group-text" for="size">평수</label>
            <select class="form-select" id="size">
                <option selected>-- 주문 평수 --</option>
                <option value="10평">10평</option>
                <option value="20평">20평</option>
                <option value="30평">30평</option>
                <option value="40평">40평</option>
                <option value="50평">50평</option>
            </select>
        </div>
        <button onclick="save_order()" type="button" class="btn btn-warning mybtn">주문하기</button>
    </div>
    <table class="table">
        <thead>
        <tr>
            <th scope="col">이름</th>
            <th scope="col">주소</th>
            <th scope="col">평수</th>
        </tr>
        </thead>
        <tbody id="order-box">
        </tbody>
    </table>
</div>
</body>
</html>


📍 스파르타피디아 - 프로젝트 세팅

  1. new project → movie 폴더 선택 후, create 클릭

  2. 폴더 구조 잡기

   1) 파일 → 새로 작성 → 디렉토리 → templates, static 파일 만들기
   2) templates 폴더 안에 index.html 파일 만들기
   3) app.py 파일 만들기
  1. 패키지 설치
   윈도우 : 좌상단 File → setting → python interpreter
   
   + 버튼 눌러 flask, pymongo, dnspython, (크롤링)bs4, requests 5개 패키지 설치


📍 스파르타피디아 - 조각 기능 구현해보기

  1. URL에서 페이지 정보 가져오기 (meta태그 스크래핑)
   API에서 수행해야하는 작업 중 익숙하지 않은 것들은,
   따로 python 파일을 만들어 실행해보고,
   잘 되면 코드를 붙여넣는 방식으로 하는 게 더 편리
  • URL만 입력했는데, 자동으로 불러와지는 부분 (제목, 썸네일 이미지, 내용)

    → 이 부분은, meta태그를 크롤링 함으로써 공통적으로 얻을 수 있음

  1. meta 태그에 대해 알아보기
   메타 태그는 <head></head> 부분에 들어가는, 
   눈으로 보이는 것<body> 외에 사이트의 속성을 설명해주는 태그들
   예) 구글 검색 시 표시 될 설명문, 사이트 제목, 카톡 공유 시 표시 될 이미지 등
   
   우리는 그 중 og:image / og:title / og:description 을 크롤링 할 예정

  1. meta 태그 스크래핑 하기
  • 연습을 위해 meta_prac.py 파일 만들어 주기

  • 크롤링 기본 코드

   import requests
   from bs4 import BeautifulSoup

   url = 'https://movie.naver.com/movie/bi/mi/basic.naver?code=191597'

   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(url,headers=headers)

   soup = BeautifulSoup(data.text, 'html.parser')

   # 여기에 코딩을 해서 meta tag를 먼저 가져와보기

  • select_one을 이용해 meta 태그 먼저 가져와보기
   image = soup.select_one('meta[property="og:image"]')
   title = soup.select_one('meta[property="og:title"]')
   desc = soup.select_one('meta[property="og:description"]')

   print(image, title, desc)
  • 가져온 meta 태그의 content 가져와보기
   title = soup.select_one('meta[property="og:title"]')['content']
   image = soup.select_one('meta[property="og:image"]')['content']
   desc = soup.select_one('meta[property="og:description"]')['content']

   print(image, title, desc)


📍 스파르타피디아 - 뼈대 준비하기

  1. 프로젝트 준비 - app.py
   from flask import Flask, render_template, request, jsonify
   app = Flask(__name__)

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

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

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

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

  1. 프로젝트 준비 - index.html
<!doctype html>
<html lang="en">

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <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=Gowun+Dodum&display=swap" rel="stylesheet">

    <style>
        * {
            font-family: 'Gowun Dodum', sans-serif;
        }

        .mytitle {
            width: 100%;
            height: 250px;

            background-image: linear-gradient(0deg, rgba(0, 0, 0, 0.5), rgba(0, 0, 0, 0.5)), url('https://cdn.pixabay.com/photo/2019/01/12/14/19/whale-3928638__480.jpg');
            background-position: center;
            background-size: cover;

            color: white;

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

        .mytitle > h1 {
            font-size: 28px;
        }

        .mytitle > button {
            width: 120px;
            height: 38px;

            font-size: 15px;

            background-color: transparent;
            color: white;

            border-radius: 50px;
            border: 2px solid white;

            margin-top: 10px;
        }

        .mytitle > button:hover {
            color: pink;
            border: 2px solid pink;
        }

        .wrap {
            max-width: 1200px;
            width: 95%;
            margin: 20px auto 20px auto;
        }

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

            margin: 20px auto 0px auto;

            box-shadow: 0px 0px 3px 0px grey;
            padding: 20px;

            display: none;
        }

        .mybtns {
            display: flex;
            flex-direction: row;
            align-items: center;
            justify-content: center;

            padding-top: 20px;
        }

        .mybtns > button {
            margin-right: 10px;
        }
    </style>
    <script>
        $(document).ready(function () {
            listing();
        });

        function listing() {
            $.ajax({
                type: 'GET',
                url: '/movie',
                data: {},
                success: function (response) {
                    alert(response['msg'])
                }
            })
        }

        function posting() {
            let url =
                $.ajax({
                    type: 'POST',
                    url: '/movie',
                    data: {sample_give: '데이터전송'},
                    success: function (response) {
                        alert(response['msg'])
                    }
                });
        }

        function open_box() {
            $('#post-box').show()
        }

        function close_box() {
            $('#post-box').hide()
        }
    </script>
</head>

<body>
<div class="mytitle">
    <h1>내 생애 최고의 영화들</h1>
    <button onclick="open_box()">영화 기록하기</button>
</div>
<div class="mypost" id="post-box">
    <div class="form-floating mb-3">
        <input id="url" type="email" class="form-control" placeholder="name@example.com">
        <label>영화URL</label>
    </div>
    <div class="input-group mb-3">
        <label class="input-group-text" for="inputGroupSelect01">별점</label>
        <select class="form-select" id="star">
            <option selected>-- 선택하기 --</option>
            <option value="1"></option>
            <option value="2">⭐⭐</option>
            <option value="3">⭐⭐⭐</option>
            <option value="4">⭐⭐⭐⭐</option>
            <option value="5">⭐⭐⭐⭐⭐</option>
        </select>
    </div>
    <div class="form-floating">
        <textarea id="comment" class="form-control" placeholder="Leave a comment here"></textarea>
        <label for="floatingTextarea2">코멘트</label>
    </div>
    <div class="mybtns">
        <button onclick="posting()" type="button" class="btn btn-dark">기록하기</button>
        <button onclick="close_box()" type="button" class="btn btn-outline-dark">닫기</button>
    </div>
</div>
<div class="mycards">
    <div class="row row-cols-1 row-cols-md-4 g-4" id="cards-box">
        <div class="col">
            <div class="card h-100">
                <img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
                     class="card-img-top">
                <div class="card-body">
                    <h5 class="card-title">영화 제목이 들어갑니다</h5>
                    <p class="card-text">여기에 영화에 대한 설명이 들어갑니다.</p>
                    <p>⭐⭐⭐</p>
                    <p class="mycomment">나의 한줄 평을 씁니다</p>
                </div>
            </div>
        </div>
        <div class="col">
            <div class="card h-100">
                <img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
                     class="card-img-top">
                <div class="card-body">
                    <h5 class="card-title">영화 제목이 들어갑니다</h5>
                    <p class="card-text">여기에 영화에 대한 설명이 들어갑니다.</p>
                    <p>⭐⭐⭐</p>
                    <p class="mycomment">나의 한줄 평을 씁니다</p>
                </div>
            </div>
        </div>
        <div class="col">
            <div class="card h-100">
                <img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
                     class="card-img-top">
                <div class="card-body">
                    <h5 class="card-title">영화 제목이 들어갑니다</h5>
                    <p class="card-text">여기에 영화에 대한 설명이 들어갑니다.</p>
                    <p>⭐⭐⭐</p>
                    <p class="mycomment">나의 한줄 평을 씁니다</p>
                </div>
            </div>
        </div>
        <div class="col">
            <div class="card h-100">
                <img src="https://movie-phinf.pstatic.net/20210728_221/1627440327667GyoYj_JPEG/movie_image.jpg"
                     class="card-img-top">
                <div class="card-body">
                    <h5 class="card-title">영화 제목이 들어갑니다</h5>
                    <p class="card-text">여기에 영화에 대한 설명이 들어갑니다.</p>
                    <p>⭐⭐⭐</p>
                    <p class="mycomment">나의 한줄 평을 씁니다</p>
                </div>
            </div>
        </div>
    </div>
</div>
</body>

</html>


📍 스파르타피디아 - POST 연습 (포스팅하기)

  1. API 만들고 사용하기 - 포스팅 API (Create → POST)
   1) 요청 정보 :  URL= /movie, 요청 방식 = POST
   2) 클라(ajax) → 서버(flask) : url, star, comment
   3) 서버(flask) → 클라(ajax) : 메시지를 보냄 (포스팅 완료!)

  1. 클라이언트와 서버 연결 확인하기
  • 서버 코드 - app.py
   @app.route("/movie", methods=["POST"])
   def movie_post():
       sample_receive = request.form['sample_give']
       print(sample_receive)
       return jsonify({'msg':'POST 연결 완료!'})
  • 클라이언트 코드 - index.html
   function posting() {
       $.ajax({
           type: 'POST',
           url: '/movie',
           data: {sample_give: '데이터전송'},
           success: function (response) {
               alert(response['msg'])
           }
       });
   }

   <button onclick="posting()" type="button" class="btn btn-dark">기록하기</button>

  1. 서버부터 만들기
  • url, star, comment 정보를 받아서 저장
  • 미리 만든 meta_prac.py 참고해서 붙여주기
  • 일전에 만들어둔 dbprac.py 파일 불러와서 만들기
  • 임포트 필수!
  @app.route("/movie", methods=["POST"])
  def movie_post():
       url_receive = request.form['url_give']
       star_receive = request.form['star_give']
       comment_receive = request.form['comment_give']

       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(url_receive, headers=headers)

       soup = BeautifulSoup(data.text, 'html.parser')

       title = soup.select_one('meta[property="og:title"]')['content']
       image = soup.select_one('meta[property="og:image"]')['content']
       desc = soup.select_one('meta[property="og:description"]')['content']

       doc = {
           'title' : title,
           'image' : image,
           'desc' : desc,
           'star' : star_receive,
           'comment' : comment_receive
       }
       db.movies.insert_one(doc)
       return jsonify({'msg':'저장 완료!'})

  1. 클라이언트 만들기
  • url, star, comment 정보 보내주기
   function posting() {
               let url = $('#url').val()
               let star = $('#star').val()
               let comment = $('#comment').val()

                   $.ajax({
                       type: 'POST',
                       url: '/movie',
                       data: {url_give: url, star_give: star, comment_give: comment},
                       success: function (response) {
                           alert(response['msg'])
                           window.location.reload()
                       }
                   });
           }

  1. 완성 확인하기
  • DB에 잘 들어갔는지 확인
  • 그 전에 연습했던 movies 콜렉션은 삭제!


📍 스파르타피디아 - GET 연습 (보여주기)

  1. API 만들고 사용하기 - 포스팅 API (Create → POST)
   1) 요청 정보 :  URL= /movie, 요청 방식 = GET
   2) 클라(ajax) → 서버(flask) : (없음)
   3) 서버(flask) → 클라(ajax) : 전체 영화를 보내주기

  1. 클라이언트와 서버 확인하기
  • 서버 코드 - app.py
   @app.route("/movie", methods=["GET"])
   def movie_get():
       return jsonify({'msg':'GET 연결 완료!'})
  • 클라이언트 코드 - index.html
   $(document).ready(function () {
               listing();
           });

           function listing() {
               $.ajax({
                   type: 'GET',
                   url: '/movie',
                   data: {},
                   success: function (response) {
                       alert(response['msg'])
                   }
               })
           }

  1. 서버부터 만들기
  • 받을 것 없이 movies에 정보를 담아서 내려주기
   @app.route("/movie", methods=["GET"])
   def movie_get():
       movie_list = list(db.movies.find({}, {'_id': False}))
       return jsonify({'movies': movie_list})

  1. 클라이언트 만들기
  • 로딩이 완료되면 listing() 함수가 불리고,
  • /movieGET 요청 들어가고,
  • response를 받아와서 카드 만들어서 붙여주기!
   $(document).ready(function () {
            listing();
        });

        function listing() {
            $.ajax({
                type: 'GET',
                url: '/movie',
                data: {},
                success: function (response) {
                    let rows = response['movies']
                    for (let i=0; i < rows.length; i++) {
                        let comment = rows[i]['comment']
                        let title = rows[i]['title']
                        let desc = rows[i]['desc']
                        let image = rows[i]['image']
                        let star = rows[i]['star']

                        let star_image = '⭐'.repeat(star)

                        let temp_html = ` <div class="col">
                                            <div class="card h-100">
                                                <img src="${image}"
                                                     class="card-img-top">
                                                <div class="card-body">
                                                    <h5 class="card-title">${title}</h5>
                                                    <p class="card-text">${desc}</p>
                                                    <p>${star_image}</p>
                                                    <p class="mycomment">${comment}</p>
                                                </div>
                                            </div>
                                        </div>`
                        $('#cards-box').append(temp_html)
                    }
                }
            })
        }

  1. 완성 확인하기
  • 동작 테스트 : 영화 기록하기 버튼 눌러서 url, 별점, 코멘트 넣고 다른 영화 기록해보기


✅ 회고

오늘은 여러 가지 패키지를 설치해서 직접 서버에 접속해서 작업을 했다.

Flask 내장함수 render_template를 이용해 html을 불러오는 것도 신기방기한데, 오늘 배운 부분이 백엔드 역할? 임에도 불구하고 너무 재밌었다.

파일 두 개를 왔다 갔다 하면서 서버와 클라이언트를 만들어 살을 덧붙이는 것 또한 흐름을 이해해나가는 과정이 즐거웠다.

앞서 배운 내용을 활용해 복습하는 것과 데이터가 DB에 저장되고 화면에 정보를 넣으면 아래에 찍히는 것도 왠지 모를 희열감이 화르르...? (변태 아님) 😊

이번 4주차는 같은 내용을 반복하는 부분이 많았는데, 배우면서 확실히 머릿속에 GET, POST가 조금씩 자리 잡혀간다고 느껴졌다.

비록 내가 처음부터 기획을 하고 하나씩 만들어가는 것은 아니어도, 다음에 이걸 활용해 아이디어를 내어 페이지 하나를 완성할 수도 있겠다는 자신감이 생겼다!!

그럼, 4주차 숙제를 하러 고고씽!!

아디오스! 뿅 🖐🏻🖐🏻🖐🏻

profile
할 수 있다고 믿는 사람은 결국 그렇게 된다 😄😊

0개의 댓글