웹개발종합반

(항해 사전스터디) 웹개발종합반 4주차 정리

JAVABOZA 2023. 4. 11. 17:17
$(document).ready(function() {
	show_order()
})
function show_order() {
    fetch('/mars').then((res) => res.json()).then((data) => {
            console.log(data);
            alert(data["msg"]);
          });
}

1주차 - html css javascript
2주차 - jquery , ajax ,api
3주차 - python , 크롤링 , mongoDB
4주차 - 미니프로젝트1, 미니프로젝트2
5주차 - 미니프로젝트3. AWS

-----------------------------------------------------------------------------------------------------------------------------------------------------------------

4주차 - 미니프로젝트1, 미니프로젝트2

 

4주차다룬 내용

  • Flask프레임워크 사용
  • get, post 요청 연습을 통한 미니프로젝트 2개

 

 

👉결과물

02.MARS -> templates -> 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" />

        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous" />
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>


    <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)),
            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() {
            fetch('/mars').then((res) => res.json()).then((data) => {
                let rows = data['result']
                $('#order-box').empty()
                rows.forEach((a) => {
                    let name    = a['name']
                    let address = a['address']
                    let size    = a['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()

            let formData = new FormData();
            formData.append("name_give", name);
            formData.append("address_give", address);
            formData.append("size_give", size);

            fetch('/mars', { method: "POST", body: formData }).then((res) => res.json()).then((data) => {
                console.log(data);
                alert(data["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">
                <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>

 

02.MARS -> venv -> app.py

(통상적으로 백엔드작업)

# pymongo와 연결 --> db
from pymongo import MongoClient
client = MongoClient('mongodb+srv://sparta:test@cluster0.eam3qp6.mongodb.net/?retryWrites=true&w=majority')
db = client.dbsparta

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 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 mars_get():
   
# 여러개 찾기 - 예시 ( _id 값은 제외하고 출력)
    mars_data = list(db.mars.find({},{'_id':False}))
    return jsonify({'result':mars_data})

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

 

1. 작업전 02.mars 프로젝트에 templates폴더 생성 프론트작업할 index.html 생성

2. 백엔드작업할 app.py파일 생성 후 새터미널 python -m venv venv (가상환경 생성, 활성화)

※인터프리터에서 Python 3.8.6('venv':'venv') 설정

3. 패키지 설치 ++> flask  /  pymongo / dnspython

-pymongo는 MongoDB 데이터베이스와 연동하기 위한 라이브러리

-dnspython는 파이썬에서 DNS프로토콜을 구현하는 라이브러리, 도메인 이름과 관련된 DNS 질의 ,응답, 레코드 생성,  

수정  ,삭제 등의 작업 수행 가능

-- 설치 여부 확인 하는 방법 : 터미널에서 pip freeze 로 확인 가능

4. 작업 시작전 가지고 올 값들 체크(프론트단) / 프론트단에서 작업이 끝난 후 msg / alert 창 띄우는지 체크 (백엔드단)

5. api 만들기 (Create -> POST방식) 

※이 프로젝트에서는 이름, 주소, 평수 저장(name, address, size)

 

6. 프론트와 백단 연결확인하기

 

        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 mars_post():
            sample_receive = request.form['sample_give']
            print(sample_receive)
            return jsonify({'msg':'POST 연결 완료!'})
        
        @app.route("/mars", methods=["GET"])
        def mars_get():
            return jsonify({'msg':'GET 연결 완료!'})
        
        if __name__ == '__main__':
            app.run('0.0.0.0', port=5000, debug=True)
function save_order() {
    let formData = new FormData();
		formData.append("sample_give", "샘플데이터");

    fetch('/mars', {method: "POST",body: formData,}).then((res) => res.json()).then((data) => {
            console.log(data);
            alert(data["msg"]);
          });
}


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

7. 백엔드 부분 먼저 작업

※ 왜냐? 먼저 담을 곳을 먼저 작업을 해야 불러오고 저장하니!

 

먼저 데이터베이스에 연결

위의 코드블록에서 'sample_give'가 아닌 내가 작업할 name / address / size값을 받아서 저장하면 됨

8.프론트단 작업

클라이언트가 작성한 정보(name, address, size)를 보내줘야 함

여기서 formData에 데이터를 넣고 보내줬다.

 

★ fetch가 요청하는거라고 생각하면 됨

 

 

이제 저장을 했으니 GET방식으로 저장한 값들을 조회하면 됨

 

마찬가지로

9. 백단과 프론트단의 연결확인하기

@app.route("/mars", methods=["GET"])
def mars_get():
    return jsonify({'msg': 'GET 연결 완료!'})
$(document).ready(function() {
	show_order()
})
function show_order() {
    fetch('/mars').then((res) => res.json()).then((data) => {
            console.log(data);
            alert(data["msg"]);
          });
}

 

10. 백단 작업

mars_data라는 변수에 list (= db안에 있는 mars테이블의 값들을 찾아)를 담아 리턴해준다.

 

 

11. 프론트단 작업

어렵게 생각하지말자!! (작업을 할때 여기서 살짝 딜레이 되었다...)

--쉽게 생각해서 DB에 담겨져 있는 정보들을 클라이언트에게 보여줘야 할 거다 그러니 그중에서 필요한 값들만

   지금은 세개밖에 없지만 DB에 다양하게 칼럼값들이 있어 여러 값들을 담았을때 필요한값들만 보여주면 그만

 

 

let rows = data['result']로 값을 불러온 다음 불러온 정보는 대게 리스트형식이니  forEach문으로 반복해서 데이터를 뽑아낸다음 넣고자 하는 틀(temp_html)에 넣는다.

 

 

여기서 한번더 정리를 해야 할것이다.

 

GET 방식

-- 💬 통상적으로 조회를 할때 많이 사용  ex)목록조회/ 구매내역조회

-- 💬 url에서 물음표?  하고 전달해주는 특징을 가지고 있음

          (   ~~~ ? key = value )

 

POST 방식

-- 💬 통상적으로 데이터를 생성 변경 삭제 요청을 할때 사용


 


 

 

👉결과물

03.PEDIA -> templates -> 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">

        integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
        integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM"
        crossorigin="anonymous"></script>

    <title>스파르타 피디아</title>


    <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://movie-phinf.pstatic.net/20210715_95/1626338192428gTnJl_JPEG/movie_image.jpg');
            background-position: center;
            background-size: cover;

            color: white;

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

        .mytitle>button {
            width: 200px;
            height: 50px;

            background-color: transparent;
            color: white;

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

            margin-top: 10px;
        }

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

        .mycomment {
            color: gray;
        }

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

        .mypost {
            width: 95%;
            max-width: 500px;
            margin: 20px auto 0px auto;
            padding: 20px;
            box-shadow: 0px 0px 3px 0px gray;

            display: none;
        }

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

            margin-top: 20px;
        }

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

        function listing() {
            fetch('/movie').then((res) => res.json()).then((data) => {
                let rows = data['result']
                $('#cards-box').empty()
                rows.forEach((a)=>{
                    let comment = a['comment']
                    let title = a['title']
                    let desc = a['desc']
                    let image = a['ogimage']
                    let star = a['star']

                    let star_repeat = '⭐'.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_repeat}</p>
                                                <p class="mycomment">${comment}</p>
                                            </div>
                                        </div>
                                    </div>`
                    $('#cards-box').append(temp_html)
                })
            })
        }

        function posting() {
            let url = $('#url').val()
            let comment = $('#comment').val()
            let star = $('#star').val()

            let formData = new FormData();
            formData.append("url_give", url);
            formData.append("comment_give", comment);
            formData.append("star_give", star);

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

        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">
                        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">
                        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">
                        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">
                        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>

 

03.PEDIA -> VENV -> app.py

(통상적으로 백엔드작업)

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

import requests
from bs4 import BeautifulSoup

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

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

@app.route("/movie", methods=["POST"])
def movie_post():
    # 웹에서 받는 값들
    url_receive = request.form['url_give']
    comment_receive = request.form['comment_give']
    star_receive = request.form['star_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'}
    # url_receive를 받아야 하니 추가
    data = requests.get(url_receive,headers=headers)
    soup = BeautifulSoup(data.text, 'html.parser')

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

    #디비에 저장
    doc = {
        'title'  :ogtitle,
        'desc'   :ogdesc,
        'ogimage':ogimage,
        'comment':comment_receive,
        'star'   :star_receive
    }
    db.movies.insert_one(doc)


    return jsonify({'msg':'저장 완료!'})

@app.route("/movie", methods=["GET"])
def movie_get():
    # 여러개 찾기 - 예시 ( _id 값은 제외하고 출력)
    all_movies = list(db.movies.find({},{'_id':False}))
    print(all_movies)
    return jsonify({'result':all_movies})

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

 

mars 작업과 큰 차이가 없는 복습차원에서 진행한 프로젝트이다.

1주차 2주차 3주차에 걸쳐 만든 영화피디아에 별점을 추가해서 디비에 넣고 그 리스트들을 출력한 것이다

 

조금 어려웠던 것은 별점을 추가 할때 valu 값을 계속해서 가지고 와서 한동안 찾아보았다.

찾아낸 결과는 아래의 이미지처럼 우선 let star = a['star']로 담은 다음

'⭐'.repeat(star) --> repeat함( 문자열반복함수)를 사용해서 구현하였다.

'⭐'

 


4주차 소감

 

mars 프로젝트에서 지금까지 배운것들을 활용해서 작업을 했는데 생각보다 쉽지만은 않았다.

내가 구현하기 애매한거 어려운거 처음인 작업들을 먼저 작업하자!! 그리고 나서 내가 익숙한 기능을 구현하자

그래야 내가 어디서 잘못됬는지 쉽게 파악을 할 수가 있다. 는 점이 크게 와닿았다.

점점 코드들이 눈에 익고 강사님의 말이 머리속으로 내용들이 그려진다.

 

회사에 다녔을때 서버팀 부장님이 해주셨던 말이 생각났다.

'작업을 하기전에 니가 무엇을 구현을 할지 충분히 생각을 많이 해보고 그려보고 해라' 라는말씀이...

 

그동안 작업을 할때는 아무 생각없이 따라식으로 했다면은 이제 점점 내가 먼저 생각을 하고 먼저 어떻게 구현을 할지 설계를 하게 되는거 같다.

 

생각하는 힘을 길러야 겠다...