드디어 첫 학습 프로젝트인 <화성땅 공동구매>를 시작한다. 썸네일로만 보던 화면을 직접 만들어 보려니 떨리고 즐겁다.
0. 프로젝트 세팅
(참고자료: Flask 기초 https://verdantjuly.tistory.com/10)
1) mars 폴더로 선택
2) app.py
3) 가상환경 잡아 주기
Mac : python3 -m venv venv
⊞ Windows : python -m venv venv
4) (venv) 잡아주기
5) templates 폴더 생성 (mars 밑에)
6) index.html 생성 (templates 밑에)
7) flask pymongo dnspython설치
pip install flask pymongo dnspython
8) clear
터미널 창 깨끗하게 함
9) 세팅을 마쳤는데 flask 에 밑줄이 그려지면서 오류가 날 때
해당 경로에 flask 가 설치되지 않았음. (참고자료)
1) venv > app.py 선택한 뒤
2) 터미널에 pip install flask
1. POST : 주문 저장하기
1) 데이터 명세
어떤 데이터를 보내 줘야 하는지 뭘 해야 하는지 확인
2) 클라이언트와 서버 연결 확인하기
- app.py 파일 실행 (python3 app.py)
- 브라우저에서 확인
- Mac 사용자는 연결 확인이 되지 않을 경우!
app.py의 포트를 5001로 변경한다. 또는 airplay 수신모드를 끈다.
catalina 사용할 때는 문제 없이 진행되었는데 ventura로 업데이트 하면서 나도 5000번 포트를 사용할 수 없었다.
나는 airplay 수신 모드를 껐는데, localhost:5000 에서 잘 작동한다.
- 철자를 절대 틀리지 말자. address_give 대신 adderess_give를 써서 6시간이나 허비했다.
3) 서버부터 만들기 app.py
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://sparta:test@cluster0.0uiki8z.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta
@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():
return jsonify({'msg':'GET 연결 완료!'})
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
4) 클라이언트 만들기 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() {
fetch('/mars').then((res) => res.json()).then((data) => {
console.log(data)
alert(data['msg'])
})
}
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>
5) 완성 확인하기
2. GET : 주문 보여주기
1) 서버 먼저 만들기
from flask import Flask, render_template, request, jsonify
app = Flask(__name__)
from pymongo import MongoClient
import certifi
ca = certifi.where()
client = MongoClient('mongodb+srv://sparta:test@cluster0.0uiki8z.mongodb.net/?retryWrites=true&w=majority', tlsCAFile=ca)
db = client.dbsparta
@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():
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)
2) 클라이언트 만들기
<!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() {
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>
3. 완성
4. 소감
오늘은 처음으로 즉문즉답에 질문을 남겼다. 5분도 되지 않아 튜터님께서 알려 주셨다. 정말 좋은 분이다. 철자 하나가 틀린 줄 모르고 6시간 동안 데이터베이스에 자료가 올라가지 않아 애먹은 것이었다. 항상 작은 부분도 놓치지 않아야 오류가 생기지 않는 점을 명심하고 귀찮아도 복사해서 붙여넣어야겠다. 다시는 같은 실수는 하고 싶지 않다. 너무 힘들었다.
'내일 배움 캠프 > 사전캠프' 카테고리의 다른 글
내일 배움 캠프 6기 미니 팀 프로젝트 [ 무비스코어 ] (1) | 2023.05.10 |
---|---|
팬명록 : 스파르타 코딩클럽 웹개발 종합반 5주차 (1) | 2023.04.30 |
버킷리스트 : 스파르타 코딩클럽 웹개발 종합반 5주차 (1) | 2023.04.30 |
스파르타피디아 : 스파르타 코딩클럽 웹개발 종합반 4주차 (1) | 2023.04.30 |