스파르타 웹개발 종합반 - 4주차
1. Flask
- API서버를 만들기 위해 자주 사용되는 Python의 마이크로 웹 프레임워크
- 패키지 설치 필요 : 파이참의 경우 file -> setting -> python interpreter
- 폴더생성 필요 : static(이미지,css파일) /tamplates(html파일)
- 기본 코드 : app.py
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)
- POST(API코드(서버)/Ajax코드(클라이언트))
@app.route('/test', methods=['POST']) #요청URL, 요청방식
def test_post():
title_receive = request.form['title_give'] #요청데이터
print(title_receive)
return jsonify({'result':'success', 'msg': '이 요청은 POST!'}) #성공메세지
$.ajax({
type: "GET",
url: "/test?title_give=봄날은간다",
data: {},
success: function(response){
console.log(response)
}
})
- GET(API코드(서버)/Ajax코드(클라이언트))
@app.route('/test', methods=['GET'])
def test_get():
title_receive = request.args.get('title_give') #요청데이터가 없는경우 없어도 됨
print(title_receive)
return jsonify({'result':'success', 'msg': '이 요청은 GET!'}) #응답데이터를 보내야함
$.ajax({
type: "GET",
url: "/test?title_give=봄날은간다",
data: {},
success: function(response){
console.log(response)
}
})
2. PyMongo
- 파이썬에서 MongoDB제어하기 위해 사용하는 패키지
- 플라스크와 마찬가지로 패키지 설치 필요
3. 퀴즈 1
- 제목 저자 리뷰를 입력하면 아래 목록에 추가됨
- 예시 : http://spartacodingclub.shop/bookreview
- 서버 코드
from flask import Flask, render_template, jsonify, request
app = Flask(__name__)
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbsparta
## HTML을 주는 부분
@app.route('/')
def home():
return render_template('index.html')
## API 역할을 하는 부분
@app.route('/review', methods=['POST'])
def write_review():
title_receive = request.form['title_give']
name_receive = request.form['name_give']
review_receive = request.form['review_give']
doc = { 'title': title_receive,
'name' : name_receive,
'review' : review_receive
}
db.bookreview.insert_one(doc)
return jsonify({'msg': '저장완료'})
@app.route('/review', methods=['GET'])
def read_reviews():
reviews = list(db.bookreview.find({}, {'_id': False}))
return jsonify({'all_reviews' : reviews})
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
- 클라이언트
<!DOCTYPE html>
<html lang="ko">
<head>
<!-- Webpage Title -->
<title>모두의 책리뷰 | 스파르타코딩클럽</title>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm"
crossorigin="anonymous">
<!-- JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<!-- 구글폰트 -->
<link href="https://fonts.googleapis.com/css?family=Do+Hyeon&display=swap" rel="stylesheet">
<script type="text/javascript">
$(document).ready(function () {
showReview();
});
function makeReview() {
let title = $('#title').val()
let name = $('#author').val()
let review = $('#bookReview').val()
$.ajax({
type: "POST",
url: "/review",
data:
{
title_give: title,
name_give : name,
review_give : review
},
success: function (response) {
alert(response["msg"]);
window.location.reload();
}
})
}
function showReview() {
$.ajax({
type: "GET",
url: "/review",
data: {},
success: function (response) {
let reviews = response['all_reviews']
for(let i = 0; i < reviews.length ; i ++){
let temp_html =
`<tr>
<td>${reviews[i]['title']}</td>
<td>${reviews[i]['name']}</td>
<td>${reviews[i]['review']}</td>
</tr>`
$('#reviews-box').append(temp_html);
}
}
})
}
</script>
<style type="text/css">
* {
font-family: "Do Hyeon", sans-serif;
}
h1,
h5 {
display: inline;
}
.info {
margin-top: 20px;
margin-bottom: 20px;
}
.review {
text-align: center;
}
.reviews {
margin-top: 100px;
}
</style>
</head>
<body>
<div class="container">
<img src="https://previews.123rf.com/images/maxxyustas/maxxyustas1511/maxxyustas151100002/47858355-education-concept-books-and-textbooks-on-the-bookshelf-3d.jpg"
class="img-fluid" alt="Responsive image">
<div class="info">
<h1>읽은 책에 대해 말씀해주세요.</h1>
<p>다른 사람을 위해 리뷰를 남겨주세요! 다 같이 좋은 책을 읽는다면 다 함께 행복해질 수 있지 않을까요?</p>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">제목</span>
</div>
<input type="text" class="form-control" id="title">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">저자</span>
</div>
<input type="text" class="form-control" id="author">
</div>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text">리뷰</span>
</div>
<textarea class="form-control" id="bookReview"
cols="30"
rows="5" placeholder="140자까지 입력할 수 있습니다."></textarea>
</div>
<div class="review">
<button onclick="makeReview()" type="button" class="btn btn-primary">리뷰 작성하기</button>
</div>
</div>
<div class="reviews">
<table class="table">
<thead>
<tr>
<th scope="col">제목</th>
<th scope="col">저자</th>
<th scope="col">리뷰</th>
</tr>
</thead>
<tbody id="reviews-box">
</tbody>
</table>
</div>
</div>
</body>
</html>
4. 퀴즈 2
- 정보(url, review)를 입력하면 해당 url 메타태그에서 이미지와 설명, 제목을 추출하여 카드 목록에 추가함
- 스크랩핑 패키지 bs4이용 해야함
- 예시 : http://spartacodingclub.shop/
- 서버 코드
from flask import Flask, render_template, jsonify, request
import requests
from bs4 import BeautifulSoup
app = Flask(__name__)
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbsparta
## HTML을 주는 부분
@app.route('/')
def home():
return render_template('index.html')
## API 역할을 하는 부분
@app.route('/memo', methods=['POST'])
def write_review():
url_receive = request.form["url_give"]
review_receive = request.form["review_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_receive = soup.select_one('meta[property="og:title"]')['content']
img_receive = soup.select_one('meta[property="og:image"]')['content']
desc_receive = soup.select_one('meta[property="og:description"]')['content']
doc = {
"title" : title_receive,
"img" : img_receive,
"desc" : desc_receive,
"review" : review_receive,
"url" : url_receive
}
db.alonememo.insert_one(doc)
return jsonify({'msg': '저장성공'})
@app.route('/memo', methods=['GET'])
def save_reviews():
reviews = list(db.alonememo.find({}, {'_id' : False}))
return jsonify({'all_reviews': reviews})
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
- 클라이언트
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Noto+Sans+KR:wght@100&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Nanum+Pen+Script&display=swap" rel="stylesheet">
<title>스파르타코딩클럽 | 부트스트랩 연습하기</title>
<style>
.wrap {
width: 900px;
margin: auto;
}
*{
font-family: 'Nanum Pen Script', cursive;
}
.card-comment{
color: blue;
font-weight: bold;
}
.card-title{
color: blue;
}
.form{
width: 400px;
margin: 30px auto 50px auto;
margin-bottom: 50px;
border: 30px solid black;
padding : 30px;
display : none;
}
</style>
<script>
$(document).ready(function(){
$("#card-box").empty();
listing();}
);
function listing() {
$.ajax({
type: "GET",
url: "/memo",
data: {},
success: function(response){
let memos = response['all_reviews']
for(let i=0; i<memos.length; i++){
let review = memos[i]['review']
let title = memos[i]['title']
let img = memos[i]['img']
let url = memos[i]['url']
let desc = memos[i]['desc']
let temp_url = `<div class="card">
<img class="card-img-top" src="${img}" alt="Card image cap">
<div class="card-body">
<a href = "${url}" class ="card-title">${title}</a>
<p class="card-text">${desc}</p>
<p class="card-comment">${review}</p>
</div>
</div>`
$("#card-box").append(temp_url);
}
}
})
}
function saving_data() {
$.ajax({
type: "POST",
url: "/memo",
data: {
url_give: $('#inputurl').val(),
review_give: $('#review').val()
},
success: function (response) {
alert(response["msg"]);
}
})
}
function openclose(){
let status = $('#post-box').css('display');
console.log(status);
if(status == 'block'){
$('#post-box').hide();
$('#btn-posting-box').text('포스팅 박스 열기');
}else{
$('#post-box').show();
$('#btn-posting-box').text('포스팅 박스 닫기');
}
}
</script>
</head>
<body>
<div class="wrap">
<div class="jumbotron">
<h1 class="display-4">나홀로 링크 메모장!</h1>
<p class="lead">중요한 링크를 저장해두고, 나중에 볼 수 있는 공간입니다</p>
<hr class="my-4">
<p class="lead">
<button onclick="openclose()" id="btn-posting-box" type="button" class="btn btn-primary">포스팅 박스 열기
</button>
</p>
</div>
<div id="post-box" class="form-post" style="display:none">
<div>
<div class="form-group">
<label for="post-url">아티클 URL</label>
<input id="inputurl" class="form-control" placeholder="">
</div>
<div class="form-group">
<label for="post-comment">간단 코멘트</label>
<textarea id="review" class="form-control" rows="2"></textarea>
</div>
<button type="button" class="btn btn-primary" onclick="saving_data()">기사저장</button>
</div>
</div>
<div id="card-box" class="card-columns">
</div>
</div>
</body>
</html>
5. 최종과제
- 쇼핑몰 완성하기 : 정보 입력후 [주문하기]버튼을 누르면 주문목록에 추가되어 보여지기
- 예시 : http://spartacodingclub.shop/homework
- 완성본 :
- 서버코드
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
client = MongoClient('localhost', 27017)
db = client.dbtest
## HTML을 주는 부분
@app.route('/')
def home():
return render_template('index.html')
@app.route('/order', methods=['POST'])
def post_order():
name_receive = request.form['name_give']
quan_receive = request.form['quan_give']
add_receive = request.form['add_give']
ph_receive = request.form['ph_give']
doc = {
'name': name_receive,
'quantity': quan_receive,
'address': add_receive,
'phone': ph_receive
}
db.orderdb.insert_one(doc)
return jsonify({'result': 'success', 'msg': '저장완료'})
@app.route('/order', methods=['GET'])
def get_post():
order= list(db.orderdb.find({}, {'_id': False}))
return jsonify({'result': 'success', 'odlist': order})
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
- 클라이언트코드
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Nanum+Myeongjo&display=swap" rel="stylesheet">
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js"
integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js"
integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl"
crossorigin="anonymous"></script>
<title>스파르타코딩클럽 | 부트스트랩 연습하기</title>
<style>
*{
font-family : 'Nanum Myeongjo', serif;
}
.wrap{
width : 500px;
margin : auto;
}
.price{
font-size : 5px;
}
.img{
width : 500px;
margin-bottom : 30px;
}
.input-group mb-3{
margin : 10px;
}
.buy{
width : 100px;
margin : 30px auto 30px auto;
}
h1{
font-weight : bold;
}
</style>
<script>
$(document).ready(function () {
get_rate();
orderlisting();
});
function get_rate(){
$.ajax({
type: "GET",
url: "http://spartacodingclub.shop/sparta_api/rate",
data: {},
success: function(response){
$('#rate').text(response['rate']);
}
})
}
function orderadd(){
let name = $('#name').val()
let quantity =$('#quantity').val()
let address = $('#address').val()
let phone =$('#phone').val()
$.ajax({
type: "POST",
url: "/order",
data: {
name_give : name,
quan_give: quantity,
add_give : address,
ph_give :phone
},
success: function (response) {
alert(response["msg"]);
}
})
}
function orderlisting(){
$.ajax({
type: "GET",
url: "/order",
data: {},
success: function(response){
let orderlist= response["odlist"];
for(let i=0; i < orderlist.length; i++){
let temp_html= `<tr>
<th scope="row">${orderlist[i]['name']}</th>
<td>${orderlist[i]['quantity']}</td>
<td>${orderlist[i]['address']}</td>
<td>${orderlist[i]['phone']}</td>
</tr>`
$('#addlist').append(temp_html)
}
}
})
}
</script>
</head>
<body>
<h1></h1>
<div class = "wrap">
<img class ="img" src = "https://m.playwithscent.co.kr/web/product/big/202012/fa1d5c14f65b6e2771fb75486fe6da59.jpg"/>
<h1>양초를 팝니다 <span style = "font-size:20px;">가격 :3000원/개</span></h1>
<p>이 양초는 사실 특별한 힘을 지니고 있어요. 양초를 켜고 소원을 빌면 짜자잔 뭐든지 이뤄지게 된답니다. 하나 사가세요! 대나무향이 아주 좋아요.</p>
<p style = "color : blue;">달러-원 환율 : <span id = "rate"> </span></p>
<!-주문자이름-!>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">주문자 이름</span>
</div>
<input type="text" class="form-control" aria-label="Username" aria-describedby="basic-addon1" id = "name">
</div>
<!-수량-!>
<div class="input-group mb-3">
<div class="input-group-prepend">
<label class="input-group-text" for="inputGroupSelect01">수량</label>
</div>
<select class="custom-select" id="quantity">
<option selected>수량을 선택하세요...</option>
<option value="1" >One</option>
<option value="2">Two</option>
<option value="3">Three</option>
</select>
</div>
<!-주소-!>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">주소</span>
</div>
<input type="text" class="form-control" aria-label="Username" aria-describedby="basic-addon1" id= "address">
</div>
<!-전화번호-!>
<div class="input-group mb-3">
<div class="input-group-prepend">
<span class="input-group-text" id="basic-addon1">전화번호</span>
</div>
<input type="text" class="form-control" aria-label="Username" aria-describedby="basic-addon1" id = "phone">
</div>
<!-주문하기-!>
<div class = "buy">
<button type="button" class="btn btn-light" onclick = "orderadd()">주문하기</button>
</div>
<!-목록-!>
<table class="table">
<thead>
<tr>
<th scope="col">이름</th>
<th scope="col">수량</th>
<th scope="col">주소</th>
<th scope="col">전화번호</th>
</tr>
</thead>
<tbody id = "addlist">
</tbody>
</table>
</div>
</body>
</html>
-->
[스파르타 5만원 할인 받고 수강하세요!]
↓
https://spartacodingclub.kr/?f_name=%EC%B5%9C%EB%AF%B8%EC%84%9C&f_uid=5f6fe706e482040009c7ec32
스파르타코딩클럽
왕초보 8주 완성! 웹/앱/게임 빠르게 배우고 내것을 만드세요!
spartacodingclub.kr