힘들었어요.여태껏 제일 어려운 수강인것 같다.
수강시간 때문에 숙제도 베껴쓰다싶이 해서 제출하였지만 아직도 확신이 가질 않는다.
목록페이지,상세페이지,메인페이지(서버페이지) 사이를 왔다갔다하니 정신을 못추겠다.나중에 시간나는대로 첨부터 다시한번 확인하는걸로 하고 일단 한단락 마무리.
복습단계에서 다시 해보고서야 알것같다.하다가 빼먹은 부호는 마지막에 전체 완성코드와 비교하면서 보충했다.
app.py
from flask import Flask, render_template, request, jsonify, redirect, url_for
from pymongo import MongoClient
import requests
app = Flask(__name__)
client = MongoClient(''mongodb://아이디:비밀번호@내 아이피', 27017)
db = client.dbsparta_plus_week2
@app.route('/')
def main():
# DB에서 저장된 단어 찾아서 HTML에 나타내기
msg = request.args.get("msg")
words = list(db.words.find({}, {"_id": False}))
return render_template("index.html", words=words, msg=msg)
@app.route('/detail/<keyword>')
def detail(keyword):
status_receive = request.args.get("status_give", "old")
# API에서 단어 뜻 찾아서 결과 보내기
r = requests.get(f"https://owlbot.info/api/v4/dictionary/{keyword}", headers={"Authorization": "Token f1ddfa0f93c711a50c23b6c7d0f15df7c93c055b"})
if r.status_code != 200:
return redirect(url_for("main", msg="Word not found in dictionary; Try another word"))
result = r.json()
print(result)
return render_template("detail.html", word=keyword, result=result, status=status_receive)
@app.route('/api/save_word', methods=['POST'])
def save_word():
# 단어 저장하기
word_receive = request.form["word_give"]
definition_receive = request.form["definition_give"]
doc = {"word": word_receive, "definition": definition_receive}
db.words.insert_one(doc)
return jsonify({'result': 'success', 'msg': f'word "{word_receive}" saved'})
@app.route('/api/delete_word', methods=['POST'])
def delete_word():
# 단어 삭제하기
word_receive = request.form["word_give"]
db.words.delete_one({"word": word_receive})
db.examples.delete_many({"word": word_receive})
return jsonify({'result': 'success', 'msg': f'word "{word_receive}" deleted'})
if __name__ == '__main__':
app.run('0.0.0.0', port=5000, debug=True)
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Sparta Vocabulary Notebook</title>
<meta property="og:title" content="Sparta Vocabulary Notebook"/>
<meta property="og:description" content="mini project for Web Plus"/>
<meta property="og:image" content="{{ url_for('static', filename='logo_red.png') }}"/>
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<!-- 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">
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<link href='{{ url_for("static", filename="mystyle.css") }}' rel="stylesheet">
<!-- 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>
<style>
.search-box {
width: 70%;
margin: 50px auto;
max-width: 700px;
}
.table {
width: 80%;
max-width: 800px;
margin: auto;
table-layout: fixed;
}
.table th {
border-top-style: none;
}
td {
background-color: white;
text-overflow: ellipsis;
overflow: hidden;
white-space: nowrap;
}
td > a, a:visited, a:hover, a:active {
color: black;
}
thead:first-child tr:first-child th:first-child {
border-radius: 10px 0 0 0;
}
thead:first-child tr:first-child th:last-child {
border-radius: 0 10px 0 0;
}
tbody:last-child tr:last-child td:first-child {
border-radius: 0 0 0 10px;
}
tbody:last-child tr:last-child td:last-child {
border-radius: 0 0 10px 0;
}
tr.highlight > td {
background-color: #34e873;
color: #6434e8;
}
tr.highlight > td > a {
color: #6434e8;
}
</style>
<script>
// console.log("{{msg}}")
{% if msg %}
alert("{{msg}}")
{% endif %}
let words = {{ words|tojson }};
let word_list = [];
for (let i = 0; i < words.length; i++) {
word_list.push(words[i]["word"])
}
// console.log(word_list)
function find_word() {
let word = $("#input-word").val().toLowerCase();
if (word == "") {
alert("please write something first:)")
return
}
if (word_list.includes((word))) {
// 리스트에 있으면 하이라이트
$(`#word-${word}`).addClass("highlight")
$(`#word-${word}`).siblings().removeClass("highlight");
$(`#word-${word}`)[0].scrollIntoView();
} else {
// 리스트에 없으면 새 단어를 위한 상세페이지로
window.location.href = `/detail/${word}?status_give=new`
}
}
</script>
</head>
<body>
<div class="wrap">
<div class="banner" onclick="window.location.href='/'">
</div>
<div class="search-box d-flex justify-content-center">
<input id="input-word" class="form-control" style="margin-right: 0.5rem">
<button class="btn btn-light" onclick="find_word()"><i class="fa fa-search"></i>
</button>
</div>
<table class="table">
<thead class="thead-light">
<tr>
<th scope="col" style="width:30%">WORD</th>
<th scope="col">MEANING</th>
</tr>
</thead>
<tbody id="tbody-box">
{% for word in words %}
<tr id="word-{{word.word}}">
<td><a href="/detail/{{word.word}}?status_give=old">{{word.word}}</a></td>
<td>
{{ word.definition|safe }}
</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</body>
</html>
detail.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>Sparta Vocabulary Notebook</title>
<meta property="og:title" content="Sparta Vocabulary Notebook"/>
<meta property="og:description" content="mini project for Web Plus"/>
<meta property="og:image" content="{{ url_for('static', filename='logo_red.png') }}"/>
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<link rel="icon" href="{{ url_for('static', filename='favicon.ico') }}" type="image/x-icon">
<!-- 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">
<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">
<link href='{{ url_for("static", filename="mystyle.css") }}' rel="stylesheet">
<!-- 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>
<style>
span.example {
color: gray;
font-size: 14px;
}
.btn-sparta {
color: #fff;
background-color: #e8344e;
border-color: #e8344e;
}
.btn-outline-sparta {
color: #e8344e;
background-color: transparent;
background-image: none;
border-color: #e8344e;
}
</style>
<script>
let word = "{{ word }}"
$(document).ready(function () {
// get_definitions()
})
function get_definitions() {
$.ajax({
type: "GET",
url: `https://owlbot.info/api/v4/dictionary/${word}`,
beforeSend: function (xhr) {
xhr.setRequestHeader("Authorization", "Token [내 토큰]");
},
data: {},
error: function (xhr, status, error) {
alert("에러 발생!");
},
success: function (response) {
console.log(response)
$("#word").text(response["word"])
if (response["pronunciation"] == null) {
$("#pronunciation".text(""))
} else {
$("#pronunciation").text(`/${response["pronunciation"]}/`)
}
let definitions = response["definitions"]
$("#definitions").empty()
for (let i = 0; i < definitions.length; i++) {
let definition = definitions[i]
let html_temp = ""
if (definition["example"] == null) {
html_temp = `<div style="padding:10px">
<i>${definition["type"]}</i>
<br>${definition["definition"]}<br>
</div>`
} else {
html_temp = `<div style="padding:10px">
<i>${definition["type"]}</i>
<br>${definition["definition"]}<br>
<span class="example">${definition["example"]}</span>
</div>`
}
$("#definitions").append(html_temp)
}
}
})
}
function save_word() {
$.ajax({
type: "POST",
url: `/api/save_word`,
data: {
word_give: "{{ word }}",
definition_give: "{{ result.definitions[0].definition }}"
},
success: function (response) {
alert(response["msg"])
window.location.href = "/detail/{{ word }}?status_give=old"
}
});
}
function delete_word() {
$.ajax({
type: "POST",
url: `/api/delete_word`,
data: {
word_give: "{{ word}}"
},
success: function (response) {
alert(response["msg"])
window.location.href = "/"
}
});
}
</script>
</head>
<body>
<div class="wrap">
<div class="banner" onclick="window.location.href = '/'">
</div>
<div class="container">
<div class="d-flex justify-content-between align-items-end">
<div>
<h1 id="word" style="display: inline;">{{ result.word }}</h1>
{% if result.pronunciation != None %}
<h5 id="pronunciation" style="display: inline;">/{{ result.pronunciation }}/</h5>
{% endif %}
</div>
{% if status=="new" %}
<button id="btn-save" class="btn btn-outline-sparta btn-lg" onclick="save_word()">
<i class="fa fa-floppy-o" aria-hidden="true"></i>
</button>
{% else %}
<button id="btn-delete" class="btn btn-sparta btn-lg" onclick="delete_word()">
<i class="fa fa-trash-o" aria-hidden="true"></i>
</button>
{% endif %}
</div>
<hr>
<div id="definitions">
{% for definition in result.definitions %}
<div style="padding:10px">
<i>{{definition.type}}</i>
<br>{{definition.definition.encode('ascii','ignore').decode('utf-8')}}<br>
{% if definition.example %}
<span class="example">{{definition.example.encode('ascii','ignore').decode('utf-8')|safe}}</span>
{% endif %}
</div>
{% endfor %}
</div>
</div>
</div>
</body>
</html>
mystyle.css
.wrap {
background-color: RGBA(232, 52, 78, 0.2);
min-height: 100vh;
padding-bottom: 50px;
}
.banner {
width: 100%;
height: 200px;
background-color: #344ce8;
background-image: url("logo_red.png");
background-position: center;
background-size: contain;
background-repeat: no-repeat;
cursor: pointer;
}
.container {
width: 80%;
max-width: 800px;
margin: 30px auto;
padding: 20px;
background-color: white;
border: solid 1px gray;
border-radius: 10px;
}