선발대

[스파르타] 웹 프로그래밍 A-Z 기초 4주차 (완강) 본문

스파르타코딩클럽/강의 정리

[스파르타] 웹 프로그래밍 A-Z 기초 4주차 (완강)

신선한 스타트 2021. 12. 16. 16:40

1. 수업 후기

 

  • 강의개수: 14개
  • 총 강의시간: 1시간 5분
  • 수업목표:
  • 1. Flask 프레임워크를 활용해서 API를 만들 수 있다.
  • 2. '화성에 땅 사기' API를 만들고 클라이언트와 연결한다.
  • 3. '스파르타 피디아' API를 만들고 클라이언트와 연결한다.

 

 이번 총 강의시간은 대략 8시간 정도 걸린 것 같다. 아무래도 서버와 클라이언트 파일을 만들고 DB에 연결하는 과정이 한 번만 보고 이해하기엔 너무 생소했다. 강의를 보고 천천히 따라 하면 그렇구나 하고 이해를 하면서 파일을 완성할 수 있는데, 직접 해보니까 어디에서부터 시작해야 하는지조차 잊어버렸다. 결국 강의의 마지막 프로젝트는 아예 순서를 적어놓고 과제할 때 참고했다. 

 

 완성된 코드가 100줄이 넘어가니까 나중에 에러가 생겨도 다시 한 줄 한 줄 보는데 시간이 걸렸다. 분명 모든 기능을 다 넣었고 순서대로 진행했는데 왜 안될까 생각했더니, 괄호가 부족하다거나 알파벳 한 자 오타가 났다거나 그런 일들이 종종 있어서 다음 기능이 실행되지 않은 것이었다. 그래도 나중에는 어마어마한 양의 코드를 확인해야 할 텐데, 지금부터라도 꼼꼼히 체크하는 습관을 들여야겠다.

 

 이 수업을 듣고 나서 이제 홈페이지를 만들고 서버와 클라이언트 각각이 받는 데이터의 종류가 어떤 것인지 이해했다. 물론 내용 정리한 것을 보고 잘 설명할 수 있는 정도이고, 나중에는 더 익숙해지도록 내용정리 없이 체득할 수 있도록 해야겠다. 이제 다음에는 직접 도메인에 배포하는 수업이던데 기대된다. 아직 기초단계이지만 더 열심히 공부해서 좋은 퀄리티의 작업물을 만들어보고 싶다. 앞으로도 화이팅~

 

2. 수업내용 정리

4-1. 4주차 오늘 배울 것
더보기
더보기
더보기

01. 오늘 배울 것 이야기 - 4주차: Flask, 미니프로젝트1, 미니프로젝트2

 

  • 오늘은 HTML, mongoDB까지 연동해서 드디어 서버 만들 것.
  • 로컬 개발환경: 클라이언트 = 서버, 같은 컴퓨터에 서버도 만들고 요청도 함. 
  • 우린 외부의 mongoDB Atlas 클라우드 서비스 이용함.

 

4-2. Flask 시작하기 - 서버 만들기
더보기
더보기
더보기

01. new project → prac

 

02. Flask 패키지 설치하고 시작!

 

  • Flask 패키지 설치!
  • 일반적으로 서버 만들 때 프레임워크로 만든다. (직접 서버 만드는 개발자는 없음)
  • 자바는 자바 프레임워크, 파이썬은 파이썬 프레임워크 ...

 

03. Flask 기초: 기본 실행

 

  • Flask 프레임워크: 서버를 구동시켜주는 편한 코드 모음. 서버 구동시 필요한 복잡한 일들을 쉽게 사용 가능.
  • 프레임워크 안 쓰면: 직접 태양초 빻고 고추장 만들기 / 프레임워크 사용시: 마트에서 구입.
  • 통상적으로 flask 서버 돌리는 파일은 app.py로 작명.
  • 아래의 코드 실행하고 브라우저에 http://localhost:5000/ 으로 접속하면 "This is Home!" 나옴.

 

# flask 시작 코드

from flask import Flask

app = Flask(__name__)

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

@app.route('/mypage')
def mypage():
    return 'This is Mypage!'

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

 

04. Flask 기초: URL 나눠보기

 

  • localhost:5000/mypage

 

4-3. Flask 시작하기 - HTML 파일 주기
더보기
더보기
더보기

01. Flask 기초: 기본 폴더구조 - 항상 이렇게 세팅하고 시작!

 

  • Flask 서버 만들 때, 항상 프로젝트 폴더 안에 총 3개의 폴더, 파일을 만들어둬야 함.
  • static 폴더 (이미지, CSS 파일을 넣어둠), templates 폴더 (html 파일 넣어둠), app.py 파일
  • 우리는 주로 templaets 만 사용할 예정임.
  • venv는 투명 폴더처럼 취급.

 

02. Flask 기초: HTML 파일 불러오기

 

  • templates 폴더 역할: HTML 파일을 담아두고, 불러오는 역할
  • 1. 간단한 index.html 파일을 templates 폴더 안에 넣어둔다.
  • 2. html 파일 불러오기: flask 내장함수 render_template을 이용한다. (프레임워크 짱~)
  • html 파일을 그냥 pycharm에서 열면, 내 컴퓨터에 있는 파일을 연 것 뿐이다.
  • 아래의 코드대로 하면 서버에서 나에게 준 것을 브라우저에서 연 것임.
  • 인터넷 환경에 배포하면 다른 사람들도 볼 수 있음.
  • 4, 5주차에는 html을 서버 통하지 않고 브라우저에서 열 일 없음.
  • 앞으로는 localhost:5000 로 서버 실행하고 확인할 것임.

 

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

## URL 별로 함수명이 같거나,
## route('/') 등의 주소가 같으면 안됩니다.

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

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

 

완성된 페이지 화면

 

4-4. Flask 시작하기 - 본격 API 만들기
더보기
더보기
더보기

01. 들어가기 전에: GET, POST 요청 타입 - 리마인드

 

  • 클라이언트가 요청할 때 '방식'이 존재함.
  • 클라이언트는 요청할 때 HTTP request method(요청 메소드)로 어떤 종류의 요청인지 응답하는 서버 쪽에 정보를 알려줌. 프론트엔드는 HTML 쪽, 백엔드는 우리가 만든 flask 서버 쪽임.
  • 가장 많이 쓰이는 방식은 GET, POST 임.
  GET POST
특징 통상적으로 데이터 조회(Read) 요청 시 사용
ex) 영화 목록 조회
통상적으로 데이터 생성(Create),
변경(Update), 삭제(Delete) 요청 시 사용

ex) 회원가입, 회원탈퇴, 비밀번호 수정
데이터 전달 URL 뒤에 물음표를 붙여 key=value로 전달
ex) google.com?q=북극곰
바로 보이지 않는 HTML body에
key:value 형태로 전달

 

02. GET, POST 요청에서 클라이언트의 데이터를 받는 방법

 

  • GET 요청 확인 Ajax 코드:
  • jQuery 임포트: 그래야지 Ajax로 요청 가능. index.html에 넣고, <script> 안에 Ajax 코드 입력.
  • 버튼 누르면 작동되도록.
  • Get 요청 API 코드: app.py 파일에 입력.
  • GET요청보다 POST 요청일 때 데이터를 더 많이 가져갈 것임.
  • 창구가 같아도 GET인지, POST인지 따라 이동하는 곳이 다름.
  • POST 방식도 마찬가지로 코드스니펫 이용해서 작성하고 연습.

 

4-5. [화성 땅 공동구매] - 프로젝트 세팅
더보기
더보기
더보기

01. 문제 분석 - 완성작부터 보기!

 

완성된 홈페이지 화면

 

02. 프로젝트 설정 - flask 폴더 구조 만들기

 

  • static, templates 폴더 + app.py 생성

 

03. 패키지 설치하기

 

  • 3개: flask, pymongo, dnspython

 

4-6. [화성 땅 공동구매] - 뼈대 준비하기
더보기
더보기
더보기

01. 프로젝트 준비 - app.py 준비하기

 

02. 프로젝트 준비 - index.html 준비하기

 

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

 

4-7. [화성땅 공동구매] - POST 연습 (주문 저장)
더보기
더보기
더보기

01. API 만들고 사용하기 - 이름, 주소, 평수 저장하기 (Create → POST)

 

 

  • 0. 미리 요약하자면
  • (1) 요청정보: URL = /mars, 요청방식 = POST
  • (2) 클라(Ajax) 서버(flask) : name, address, size
  • (3) 서버(flask) 클라(ajax) : 메세지를 보냄 (주문 완료!)

 

  • 1. 클라이언트와 서버 연결 확인하기
  • 서버코드: app.py, 클라이언트 코드: 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=["POST"])
def mars_post():
    sample_receive = request.form['sample_give']
    print(sample_receive)
    return jsonify({'msg': 'POST 연결 완료!'})

 

  • 2. 서버부터 만들기
  • name, address, size 정보 받아서 저장함.
  • dbprac 파일의 예시문들을 이용해서 활용

 

# 저번에 DB에 자료저장하는 것 참고해서 그대로 작성

@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.orders.insert_one(doc)

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

 

  • 3. 클라이언트 만들기
  • 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() // 새로고침
        }
    });
}

 

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

 

  • 5. 최종 정리
  • (1) 버튼 누르면 index.html 파일에서 save_order() 실행
  • (2) name, address, size를 jQuery로 가져온 뒤에 data 항목에 실어보냄.
  • (3) 실어보낸 데이터는 app.py 파일의 POST 창구에서 약속한대로 받고 그 이후의 작업이 수행됨.
  • (4) 작업 안에는 DB에 데이터 저장하는 것도 포함되어있음.
  • (5) app.py 작업이 끝나고 return 하면서 '주문완료'로 내려줌.
  • (6) index.html 파일에서 성공적으로 작동하였으므로 '주문완료'를 받아서 alert, reload 함.

 

4-8. [화성땅 공동구매] - GET 연습 (주문 보여주기)
더보기
더보기
더보기

01. API 만들고 사용하기 - 저장된 주문을 화면에 보여주기 (Read → GET)

 

  • 0. 미리 요약하자면
  • (1) 요청정보: URL = /mars, 요청방식 = GET
  • (2) 클라(Ajax) → 서버(flask) : 없음 # 로딩 완료되자마자
  • (3) 서버(flask) 클라(ajax) : 전체 주문을 보내주기

 

  • 1. 클라이언트와 서버 확인하기
  • 서버코드: app.py, 클라이언트 코드: index.html

 

  • 2. 서버부터 만들기
  • 따로 받을 것 없이 orders 에 주문정보를 담아서 내려주기만 하면 끝

 

  • 3. 클라이언트 만들기
  • 응답 잘 받아서 for문으로 붙여주면 끝

 

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

 

02. 전체 완성 코드

 

## 서버 코드: app.py

@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():
    order_list = list(db.mars.find({}, {'_id': False}))
    return jsonify({'orders': order_list})
    
    
    
## 클라이언트 코드 index.html

<script>
        $(document).ready(function () { // 로딩이 되자마자
            show_order();
        });

        function show_order() { // 로딩이 되자마자
            $.ajax({
                type: 'GET',
                url: '/mars',
                data: {},
                success: function (response) { // response에 orders 있음
                    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>

 

4-9. [스파르타 피디아] - 프로젝트 세팅
더보기
더보기
더보기

01. 문제 분석 - 완성작부터 보기!

 

완성된 홈페이지 화면

 

02. 프로젝트 준비 - flask 폴더 구조 만들기

 

  • static, templates 폴더 + app.py

 

03. 패키지 설치하기

 

  • 5개: flask, pymongo, dnspython, bs4(크롤링), requests(크롤링)

 

4-10. [스파르타피디아] - 조각 기능 구현해보기
더보기
더보기
더보기

01. 프로젝트 준비 - URL에서 페이지 정보 가져오기 (meta 태그 스크래핑)

 

  • 조각기능: API에서 수행해야하는 작업 중 익숙하지 않은 것들은 따로 파이썬 파일 만들어서 실행.
  • 잘 되면 코드 붙여넣는 방식으로 하는 게 편함.
  • URL만 입력했는데도 자동으로 불린 부분들이 있음. (ex. 스파르타피디아 - 제목, 썸네일 이미지, 내용)
  • 얘네들 크롤링해서 같이 DB에 넣어주는 것이 핵심임.

 

  • meta 태그: 눈에 보이는 것(body) 외에 <head>에 들어가며 사이트 속성을 설명해주는 태그 
  • 카카오톡에 URL 보내면 이미지랑 제목, 설명도 함께 화면에 전송됨.
  • 우리 홈페이지도 심어놓으면 카톡에 URL 보냈을 때 같은 방식으로 보임. 안 심어놓으면 안 나옴.
  • select_one으로 meta tag 가져올 수 있음

 

4-11. [스파르타피디아] - 뼈대 준비하기
더보기
더보기
더보기

01. 프로젝트 준비 - app.py, index.html 준비하기 

 

4-12. [스파르타피디아] - POST 연습 (포스팅하기)
더보기
더보기
더보기

01. API 만들고 사용하기 - 포스팅 API (Create → POST) // '기록하기' 만드는 파트

 

  • 0. 미리 요약하자면
  • (1) 요청 정보: URL = /movie, 요청 방식: POST
  • (2) 클라(ajax) → 서버(flask): url, star, comment 
  • (3) 서버(flask) → 클라(ajax): 메세지를 보냄 (포스팅 완료!)
  • // 서버는 URL을 가지고 크롤링한다. 그 후, image, title, description, star, comment 를 DB에 저장. 

 

  • 1. 클라이언트와 서버 연결 확인하기
  • 서버코드: app.py, 클라이언트 코드: index.html

 

  • 2. 서버부터 만들기
  • url, star, comment 정보를 받아서 저장함.
  • 위에서 만든 meta tag랑 dbprac 파일 활용.

 

  • 3. 클라이언트 만들기
  • url, star, comment 정보 보내주기.

 

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

 

4-13. [스파르타피디아] - GET 연습 (보여주기)
더보기
더보기
더보기

01. API 만들고 사용하기 - 보여주기 API (Read → GET)

 

  • 0. 미리 요약하자면
  • (1) 요청 정보: URL = /movie, 요청 방식: GET
  • (2) 클라(ajax) → 서버(flask): (없음)
  • (3) 서버(flask) → 클라(ajax): 전체 영화를 보여주기

 

  • 1. 클라이언트와 서버 확인하기
  • 서버 코드: app.py, 클라이언트 코드: index.html

 

  • 2. 서버부터 만들기
  • 따로 데이터 받을 필요없이 orders에 주문정보 담아서 내려주기만 하면 됨.

 

  • 3. 클라이언트 만들기
  • 응답을 잘 받아서 for문으로 붙여주기.

 

  • 4. 완성 확인하기
  • 동작 테스트: 화면 새로고침하면 DB에 저장된 리뷰가 잘 나타나는가.

 

02. 전체 완성 코드

 

## 서버코드: app.py

@app.route("/movie", methods=["POST"])
def movie_post():
    url_receive = request.form['url_give'] # 1. [POST] 받아올 변수 설정
    star_receive = request.form['star_give']
    comment_receive = request.form['comment_give']

    headers = { # 2. [POST] 크롤링 코드 가져오기
        '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) # 3. [POST] 여기에 url_receive 넣어주기
    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']
    # 데이터 5개 준비 완료 (title, image, desc, star, comment)

    # 4. [POST] DB에 데이터 저장
    doc = {
        'title': title,
        'image': image,
        'desc': desc,
        'star': star_receive,
        'comment': comment_receive
    }
    db.movies.insert_one(doc)

    # 5. 원하는 형태로 수정
    return jsonify({'msg':'POST 저장 완료!'})

@app.route("/movie", methods=["GET"])
def movie_get():
    # 9. [GET] 전체 데이터 가져오기
    movie_list = list(db.movies.find({}, {'_id': False}))

    # 10. [GET] movie에 movie_list 할당해서 가져간다 // 서버 끝
    return jsonify({'movies': movie_list})

 

 

## 클라이언트 코드: index.html

<script>
    $(document).ready(function () {
        listing();
    });

    // 11. [GET] 로딩이 완료되면 listing 함수 실행, get 요청해서 movie로 들어감
    function listing() {
        $('#cards-box').empty()
        $.ajax({
            type: 'GET',
            url: '/movie',
            data: {},
            success: function (response) {
                // 11, 13. [GET] 그리고 response 받아와서 카드로 붙여주기
                let rows = response['movies']
                for (let i = 0; i < rows.length; i++) {
                    let comment = rows[i]['comment']
                    let desc = rows[i]['desc']
                    let image = rows[i]['image']
                    let star = rows[i]['star']
                    let title = rows[i]['title']

                    // 15. [GET] 별 모양 찍어주기
                    let star_image = '⭐'.repeat(star)

                    // 14. [GET] 카드 박스 통째로 가져와서 붙여준다. '' 없음
                    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>`

                    // 16. [GET] id 찾아서 붙여주기
                    $('#cards-box').append(temp_html)
                    // console.log(response['movies']) // 12. [GET] app.py 에서 return movies 로 준다.
                }
            }
        })
    }


    function posting() {
        // 6. 클라이언트에게 입력 받은 데이터, 변수에 저장
        let url = $('#url').val()
        let star = $('#star').val()
        let comment = $('#comment').val()

        $.ajax({
            type: 'POST',
            url: '/movie',
            // 7. 서버에 약속한대로 가져가기
            data: {url_give: url, star_give: star, comment_give: comment},
            success: function (response) {
                alert(response['msg'])
                window.location.reload() // 8. 새로고침, 이제 홈페이지에서 기록하면 DB로 저장
            }
        });
    }

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

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

 

4-14. 4주차 끝 & 숙제 설명
더보기
더보기
더보기

01. 1주차의 팬명록 완성하기

 

완성된 홈페이지 화면

 

 

  • 필요한 기능:
  • 1. 사용자로부터 정보 입력받기
  • 2. 정보 입력되면 자동으로 화면에 붙여주기

 

  • 필요한 패키지: Flask, pymongo, dnspython

 

##서버 파일: app.py

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

    doc = { # 딕셔너리는 키: 밸류로 구성됨.
        'name': name_receive,
        'comment': comment_receive
    }

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

@app.route("/homework", methods=["GET"])
def homework_get():
    comment_list = list(db.homework.find({}, {'_id': False}))
    return jsonify({'comments': comment_list})

 

 

// 클라이언트 파일: index.html

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

        function set_temp() {
            $.ajax({
                type: "GET",
                url: "http://spartacodingclub.shop/sparta_api/weather/seoul",
                data: {},
                success: function (response) {
                    $('#temp').text(response['temp'])
                }
            })
        }

        function save_comment() {
            let name = $('#name').val()
            let comment = $('#comment').val()

            $.ajax({
                type: 'POST',
                url: '/homework',
                data: {'name_give': name, 'comment_give': comment},
                success: function (response) {
                    alert(response['msg'])
                    window.location.reload()
                }
            })
        }

        function show_comment() {
            $.ajax({
                type: "GET",
                url: "/homework",
                data: {},
                success: function (response) {
                    let rows = response['comments']
                    for (let i = 0; i < rows.length; i++) {
                        let name = rows[i]['name']
                        let comment = rows[i]['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>`
                        $('#comment-list').append(temp_html)


                    }
                }
            });
        }
    </script>
Comments