티스토리 뷰

카테고리 없음

스파르타 코딩 클럽 4주차 교육 (서버)

반려견 반려묘 이야기 2022. 8. 13. 17:50
반응형

Python을 열심히 배운 이유. (서버에 올리기 위해서.)

윈도우 : 좌상단File → setting → Python interpreter -> Flask검색 -> 패키지 설치.

 

 

Flask 서버 = flask 프레임워크를 사용해서 만드는 것임. (직접 서버를 만드는 개발자는 없음)

서버용 파일은 app.py로 파일명을 통일한다.

 

 

서버를 굴리고, http://localhost:5000/ 를 하면 서버가 만들어지는 것.

 

 

 

localhost : 내 컴퓨터에서 서버를 돌리는 것이고, 서버에 요청을 해서 크롬에 띄우겠다.

 

 

 

프레임워크 = 기본 구조 골격이 있고, 이것은 마음대로 쓰면 안됨. 내가 따라가야 함.

 

static폴더 (이미지, CSS 파일)

templates (html 파일)

app.py

 

3가지는 꼭 있어야 함

 

 

templates 폴더에 index.html 폴더를 넣고, 거기에서 코딩.

아래 코드를 실천하면 index.html을 불러올 수 있다.

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

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


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

 

 

데이터를 가져오는 방식.

 

GET : 데이터 조회 (Read용)

POST : 데이터 생성(Create), 변경 (Update), 삭제(Delete)

 

 

GET 코드에 대한 app.py 파일. (API)

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

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


@app.route('/test', methods=['GET'])
def test_get():
   title_receive = request.args.get('title_give') #index.html의 title_give를 가져와라
   print(title_receive) #title_give의 값을 출력해라 (아래 index.html에서 봄날은 간다로 정의)
   return jsonify({'result':'success', 'msg': '이 요청은 GET!'}) #리턴해서 다시 돌려줘라

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

위코드가 서버상에서 돌았다는 증거 (GET요청 API가 동작 한 것)

 

콘솔 상에서 정상적으로 돌았기 때문에 아래 문장이 출력되는 것

 

※중요※ (여기서 /test라는 것이 API의 역할을 하는 것. API는 창구 (출금 창구 = 출금만, 입금 창구 = 입금만)

 

GET코드에 대한 index파일.

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <script>
        function hey() {
            $.ajax({
                type: "GET", #GET타입으로 데이터를 전달한다. (READ한다)
                url: "/test?title_give=봄날은간다", #title_give라는 변수에 봄날은 간다를 넣는다.
                data: {},
                success: function (response) {
                    console.log(response) #url에서 얻어온 값을 출력한다.
                }
            })
        }
    </script>
</head>
<body>
<h1>나의 웹 페이지!</h1>
<button onclick="hey()">첫버튼</button>
</body>
</html>

동작하는 순서가 중요.

 

기본 서버구동 : flask를 통해서 app.py (서버)가 구동된다. > index.html이 불러와진다.

서버내 동작 :

1. index.html에 있는 버튼이 눌린다.

2. JQuery(Ajax)문장이 실행된다.

3. GET, POST타입으로 특정 API에서 데이터를 전달한다

4. app.py에 기록된 API창구를 불러온다.

5. Ajax에서 받았던 GET, POST 타입중 하나로 실행한다

6. API가 해야하는 동작을 처리하고 RETURN을 해준다

7. app.py의 return이 성공하면 index.html에서 추가적인 동작을 한다.

 

화성땅 프로젝트 기본.

1. 폴더 설정 > 경로 체크 > venv > Python 3.8 체크 

2. 폴더 생성 (static (이미지/CSS), templates(html))

3. app.py 생성

4. 패키지 추가 (프로젝트 > 설정 > Python 인터프리터)

    flask(서버), pymongo(DB접근), dnspython

5. https://cloud.mongodb.com/ 에서 MongoDB 띄워두기.

 

준비 완료.

 

Tip. TemplateNotFound : index.html이 무엇인가? 

 

index.html파일을 templates폴더가 아닌 다른 경로에 넣었을 때 문제가 생기는 것. (마찬가지로 CSS, 이미지는 static 폴더에 생성해야한다.)

 

 

주문을 하는것.

주문을 보여주는 것 두가지만 하면 됨.

 

화성땅 사기의 미션.

1. 요청 정보 : URL= /mars , 요청 방식 = POST

2. 클라(ajax) → 서버(flask) : name , address , size  / 파일로 치면 index.html

3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (주문 완료!) / 파일로 치면 app.py

 

1) 클라이언트와 서버 연결 확인하기

2) 서버부터 만들기


@app.route("/mars", methods=["POST"])
def web_mars_post():
    # 클라이언트에서 전달해준 자료 name, address, size를 받는다.
    name_receive = request.form['name_give']
    address_receive = request.form['address_give']
    size_receive = request.form['size_give']

    # DB에 어떤 타입의 데이터로 넣을지 정의한다. dic타입 데이터임.
    doc = {
        'name' : name_receive,
        'address' : address_receive,
        'size' : size_receive
    }

    # DB에서 mars라는 공간에 doc데이터를 넣는다.
    db.mars.insert_one(doc)

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

 

3) 클라이언트 만들기

function save_order() {
	#html에 있는 id 값이 있는 필드의 값들을 변수에 넣는 행위
    let name = $('#name').val()
    let address = $('#address').val()
    let size = $('#size').val()
	
    #서버로 데이터를 넘길 때 POST타입으로 /mars라는 API에 DATA를 전달
    #중요한 포인트 : 서버에 정의된 데이터는 XXX_give로 index.html에서는 못봄
    #허나 개발자는 알고 있기 때문에 xxx_give : 변수로 설정이 가능한것
     $.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) 완성하기

 

 

(데이터를 읽을 때(GET)는?)

GET방식 = 클라이언트에서 서버로 보낼 것이 없음

서버에서 클라이언트로 전체 주문한 내역을 보여줄 것.

 

<서버부분>


@app.route("/mars", methods=["GET"])
def web_mars_get():
    #  DB에서 모든 리스트를 다 가져온다. (그것은 order_list에 넣는다.
    order_list = list(db.mars.find({}, {'_id': False}))
    # orders라는 데이터 타입(키)에 order_list(DB)를 넣는다.
    return jsonify({'orders':order_list})

 

<클라이언트 부분>

function show_order() {
    $.ajax({
        type: 'GET',
        url: '/mars',
        data: {},
        success: function (response) {
            // 서버에서 가져온 데이터
            let rows = response['orders']
            for (let i = 0 ; i < rows.length; i++){
                //서버에서 가져온 데이터(DB)를 클라이언트에 뿌리기 위한 작업
                let name = rows[i]['name']
                let address = rows[i]['address']
                let size = rows[i]['size']

                //클라이언트의 html을 바꿔서 화면상 변화를 만드는 것
                let temp_html = `<tr>
                                    <td>${name}</td>
                                    <td>${address}</td>
                                    <td>${size}</td>
                                </tr>`
                                
                                
				//출력하는 위치의 id값 (여기선 tbody에 뿌려주기 때문에 tbody id="order-box"
                $('#order-box').append(temp_html)
            }

        }
    });

 

 

영화평점의 핵심.

 

1. URL을 들어가서 영화에 있는 이미지, 제목, 설명을 크롤링해서 DB에 넣어주고

다시 뿌려주는 것이 핵심. (기록하기 기능)

 

2. 가져온 것을 카드모양으로 붙여주는 것.

 

 

영화평점 프로젝트 기본.

1. 폴더 설정 > 경로 체크 > venv > Python 3.8 체크 

2. 폴더 생성 (static (이미지/CSS), templates(html))

3. app.py 생성

4. 패키지 추가 (프로젝트 > 설정 > Python 인터프리터)

    flask(서버), pymongo(DB접근), dnspython + 크롤링을 위해서 requests, bs4 설치

 

크롤링 하는 것 연습 다시하기.

왜 먼저하느냐? 

 

서버를 올리기 전에 프로젝트의 기능이 도는지 안도는지 알아야 한다 (이런 것을 조각 기능이라 한다.)

 

 

meta 태그. 

누군가 카톡에 링크를 공유했는데 이미지, 제목, 설명이 보이는 이유. (meta 태그를 설정했기 때문에)

 

크롤링 조각 기능

import requests
from bs4 import BeautifulSoup

# 크롤링할 사이트의 주소
url = 'https://movie.naver.com/movie/bi/mi/basic.naver?code=91597'

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')

# 크롤링을 했을 때 페이지에 있는 값을 가져 오는 것. (head에서 meta태그를 찾으면 됨)
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(title, image, desc)

영화평점 프로젝트 기본.

1. 요청 정보 : URL= /movie , 요청 방식 = POST

2. 클라(ajax) → 서버(flask) : url , star , comment

3. 서버(flask) → 클라(ajax) : 메시지를 보냄 (포스팅 완료!)

 

 

 

<서버쪽 코드>

#크롤링하는 것
import requests
from bs4 import BeautifulSoup

#DB사용하는것
from pymongo import MongoClient
client = MongoClient('mongodb+srv://test:sparta@cluster0.klhr9in.mongodb.net/Cluster0?retryWrites=true&w=majority')
db = client.dbsparta

@app.route("/movie", methods=["POST"])
def movie_post():
    # 클라에서 post 방식으로 들어온 정보를 변수에 저장.
    url_receive = request.form['url_give']
    star_receive = request.form['star_give']
    comment_receive = request.form['comment_give']

    # 클라에서 받아온 url_receive로 가서, 크롤링을 해오는 것 (title, image, desc)
    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')

    # 크롤링을 했을 때 페이지에 있는 값을 가져 오는 것. (head에서 meta태그를 찾으면 됨)
    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':'저장 완료'})

 

클라이언트 쪽 코드 <POST 방식 = 데이터를 생성, 변경, 삭제할 때 사용)>

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. 요청 정보 : URL= /movie , 요청 방식 = GET

2. 클라(ajax) → 서버(flask) : (없음)

3. 서버(flask) → 클라(ajax) : 전체 영화를 보내주기

 

 

 

서버쪽

@app.route("/movie", methods=["GET"])
def movie_get():
    movie_list = list(db.movies.find({}, {'_id': False}))
    return jsonify({'movies':movie_list})

 

클라이언트 쪽

 

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)

            }
        }
    })

 

 

팬명록 과제.

 

2가지 기능

1 - 데이터 가져오기

2 - 데이터 뿌리기

 

 

1 - 데이터 가져오기

1. 요청 정보 : URL= /homework, 요청 방식 = POST

2. 클라(ajax) → 서버(flask) : name, comment

3. 서버(flask) → 클라(ajax) : 방명록을 남김 (포스팅 완료!)

 

2 - 데이터 뿌리기

1. 요청 정보 : URL= /homework , 요청 방식 = GET

2. 클라(ajax) → 서버(flask) : (없음)

3. 서버(flask) → 클라(ajax) : 전체 방명록 리스트를 뿌려주기

 

<서버쪽 코드>

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

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


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



# 1 - 데이터 가져오기
#
# 1. 요청 정보 : URL= /homework, 요청 방식 = POST
# 2. 클라(ajax) → 서버(flask) : name, comment
# 3. 서버(flask) → 클라(ajax) : 방명록을 남김

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

    return jsonify({'msg':'방명록을 남김'})

# 2 - 데이터 뿌리기
#
# 1. 요청 정보 : URL= /homework , 요청 방식 = GET
# 2. 클라(ajax) → 서버(flask) : (없음)
# 3. 서버(flask) → 클라(ajax) : 전체 방명록 리스트를 뿌려주기


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

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

 

<클라이언트쪽 코드>

<!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://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcS_i2OTPKZUZ_hhI-WMAqkmAet0KHaWsZvGEg&usqp=CAU');
            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() {
            $.ajax({
                type: "GET",
                url: "http://spartacodingclub.shop/sparta_api/weather/seoul",
                data: {},
                success: function (response) {
                    $('#temp').text(response['temp'])
                }
            })
        }

		//클라이언트에서 서버로 자료를 넘기는 과정 (input 박스에 넣은 값을 DB로 옮김)
        function save_comment() {
        	//input박스에 정의해둔 것을 변수로 저장한 것.
            let name = $('#name').val()
            let comment = $('#comment').val()
            
            //data를 전달할 때 주의사항 (서버에서 정해준 규칙 (name_give, comment_give)를 틀리면 안됨.)
            //서버에서 저장한 데이터 타입&이름이 맞아야 DB에 입력이 될 수 있음)

            $.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) {
                	//서버에 있는 DB에서 가져옴 (comments가 서버쪽 DB에 있는 데이터)
					let rows = response['comments']
                    for (let i = 0 ; i < rows.length ; i++){
                    	//rows가 서버에서 가져온 DB이니 DB안에 있는 DIC타입 데이터를 쓸 수 있음)
                        let name = rows[i]['name']
                        let comment = rows[i]['comment']

						//클라이언트 쪽에서 DB값을 화면에 뿌려주는 기능
                        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>아이유 팬명록</h1>
    <p>현재기온 : <span id="temp"></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>
</body>
</html>

 

[틀릴뻔한 부분.]

$('#comment-list').append(temp_html)

이것이 하나씩 불러와서 찍어주는 놈인데, for안에 들어가야지만 1개씩 출력이 됨.

(for문 밖에 정의하니 하나도 안찍힘)

 

위치가 정말 중요하다.

반응형
댓글