촬리의늘솔길

웹개발+/2주차 필기,개발일지 본문

✍~2022/WEB

웹개발+/2주차 필기,개발일지

리촬리 2021. 7. 18. 18:16

 

정적 웹페이지 vs. 동적 웹페이지

 

동적 웹페이지의 종류

Client-side rendering (CSR)

자바스크립트에 데이터를 포함해서 보낸 후, 클라이언트 쪽에서 HTML을 완성하는 방법

 

Server-side rendering (SSR)

서버 쪽에서 템플릿 HTML에 데이터를 끼워넣어 완성된 형태의 HTML을 보내주는 방법

 

복합적인 방법

클라이언트 쪽에서 Ajax 요청을 보내서 서버에서 데이터를 받아와 HTML을 완성하는 방법

 

서버에 요청들어오면

html에 자바스크립트 심어서 보내주고,

페이지 드고나면 자바스크립트가 돌면서 

ajax가 서버로 요청을 보내서 데이터를 받아와서 채워넣음

 

어렵다.

 

Jinja2 템플릿 언어

Flask 프레임워크에서 사용하는 템플릿 언어 '템플릿'이 되는 HTML 문서에 데이터가 들어갈 곳을 표시해놓는 역할을 합니다!

 


 

플라스크로 멀티페이지 사이트 만들기 : 기초 알기

상세 페이지로 가는 하이퍼링크는 이렇게 만듭니다.

<a href="/detail">상세 페이지로 가기</a>

 

메인 페이지로 돌아가는 버튼은 이렇게 만들 수 있겠죠!

// <head> 안에 <script> 태그 안에 정의하기

function to_main() { window.location.href = "/" }

 

<!-- 버튼에 함수 연결하기 <body>태그안에 -->

<button onclick="to_main()">메인으로 돌아가기</button>


@app.route('/')
def main():
myname = "Sparta"
return render_template("index.html", name=myname)

# name이라는이름으로 값을 보내줌

 

index.html은 하나인데 서버에서 상황에 맞게 값을 바꿔 끼워넣음

<h3>안녕하세요~!{{ name }}!</h3>


Ajax이용해서 값 끼워넣기

<ul> 태그 : 순서없는 리스트

ul태그에 끼워넣으려면 html쪼가리를 만들어서 끼워넣어야 하기때문에

let temp_html = `<li>${gu_name}:${gu_mise}</li>`
$("#gu-list").append(temp_html)

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js"></script>
    <script>
        $(document).ready(function () {
            get_list()
        })

        function get_list() {
            $.ajax({
                type: "GET",
                url: "http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99",
                data: {},
                success: function (response) {
                    let rows = response["RealtimeCityAir"]["row"];
                    console.log(rows)
                    $("#gu-list").empty()
                    for (let i=0;i<rows.length; i++){
                        let gu_name = rows[i]["MSRSTE_NM"]
                        let gu_mise = rows[i]["IDEX_MVL"]
                        console.log(gu_name,gu_mise)
                        if (gu_mise >=60){
                            let temp_html = `<li>${gu_name}:${gu_mise}</li>`
                            $("#gu-list").append(temp_html)
                        }

                    }
                }
            })
        }
    </script>
</head>
<body>
    <h1>상세페이지</h1>
    <button onclick="window.location.href = '/' ">메인으로 돌아가기</button>
    <ul id = "gu-list">
        <li>미세먼지</li>

    </ul>

</body>
</html>

jinja2이용해서 값 끼워넣기

 

전에 설정해줘야함 (파이참, 나 jinja2쓸거니까 알아서 색칠하구 자동완성 좀해줭)

 

settings들어감

이렇겡!

 

 

<li>{{ rows[0]["MSRSTE_NM" ]}}:{{ rows[0]["IDEX_MVL"] | int }}</li>

| 기호(파이프)를 쓰고 int지정가능

 

{% set gu_name = rows[0]["MSRSTE_NM" ] %}
{% set gu_mise = rows[0]["IDEX_MVL"] | int %}

변수이름 설정 가능

 

 

반복문에 넣어줌

{% for row in rows %}
{% set gu_name = row["MSRSTE_NM" ] %}
{% set gu_mise = row["IDEX_MVL"] | int %}
{% if gu_mise >= 70 %}
<li>{{ gu_name }}:{{ gu_mise }}</li>
{% endif %}
{% endfor %}

 

get 요청 보내서 받기

http://localhost:5000/detail?word_give=hi

word_receive = request.args.get("word_give")
print(word_receive)
# get요청에서 보낸 파라미터를 위와같이 받을 수 있음

 

받은걸 html에 끼워넣어서 보여주기

app.py

return render_template("detail.html", rows = rows,word= word_receive

detail.html

<h3>받은 단어는{{ word }}</h3>

 

 

detail/하고 뒤에 넘어오는 글자들을 변수에 저장해서 넘기는 방법

@app.route('/detail/<keyword>')
def detail(keyword):
r = requests.get('http://openapi.seoul.go.kr:8088/6d4d776b466c656533356a4b4b5872/json/RealtimeCityAir/1/99')
response = r.json()
rows = response['RealtimeCityAir']['row']
word_receive = request.args.get("word_give")
print(word_receive)
# get요청에서 보낸 파라미터를 위와같이 받을 수 있음
return render_template("detail.html", rows = rows,word= keyword)


사전 API 사용하기

키워드 입력해준걸 받아서 단어관련 정보 출력

@app.route('/detail/<keyword>')
def detail(keyword):
r = requests.get(f"https://owlbot.info/api/v4/dictionary/{keyword}", headers={"Authorization": "Token fc4c687f7f2bbaf3808c5499ec484799f01dc28a"})
result = r.json()
print(result)

 

콘솔에서도 가능

 


플라스크로 멀티페이지 사이트 만들기 : 기본구조 (로직)

 

내 단어장에 단어가 있다 ->  보여줌

내 단어장에 단어가 없다 ->  사전 api 에서 찾아서 가져옴 ->추가버튼 누르면 내 단어장에 추가 -> 추가버튼은 삭제버튼으로 변경되어야함


플라스크로 멀티페이지 사이트 만들기 : 본격적으로 시작해보자

배경과 배너

css와 html 설정해주고 콘솔창에 들어가보면

체크박스를 해제 해보면서 어떤게 바뀌는지 바로바로 알 수 있음.

 

아이콘 관련된 코드까지 알려주는 착한사이트

https://fontawesome.com/v4.7.0/

 

Font Awesome, the iconic font and CSS toolkit

Get 1535 icons right now with FA Free, plus another 7020 icons with Pro, which also gets you another 53 icon category packs as we finish them! Our all-new SVG with JavaScript gives you all the power of SVG without the usual hassle. Ligatures for easier des

fontawesome.com

font-awesome에 있는 클래스를 가져다가 쓰려면 링크를 head에 넣어줘야함

<link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">

부트스트랩처럼!

<button></button>태그 사이에 넣어주면됨

 


ajax를 이용해서 문자받아서 끼워넣어서 단어 api이용하기

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

app.py에서 받아온 word변수를 script태그 바로 안에 적어둬서 다른곳에서도 가져다가 쓸 수 있게 됨.

내토큰을 넣어줘야함 fc4c687f7f2bbaf3808c5499ec484799f01dc28a

 

 

콘솔창에서 나오는 결과 확인

definitions 에 definition이나 type과 같이 키를 이용해서 품사와 예문과 뜻이 들어있음을 확인가능

 

function get_definitions() {
        $.ajax({
            type: "GET",
            url: `https://owlbot.info/api/v4/dictionary/${word}`,
            beforeSend: function (xhr) {
                xhr.setRequestHeader("Authorization", "Token fc4c687f7f2bbaf3808c5499ec484799f01dc28a" )},
            data: {},
            error: function (xhr, status, error) {
                alert("에러 발생!");
            },
            success: function (response) {
                console.log(response)
                $("#word").text(response["word"])
                $("#pronunciation").text(`/${response["pronunciation"]}/`)
                let definitions = response["definitions"]
                for (let i =0; i<definitions.length; i++){
                    let definition = definitions[i]
                    let html_temp = `<div id="definitions">
                                        <div style="padding:10px">
                                            <i>${definition["type"]}</i>
                                            <br>${definition["definition"]}<br>
                                            <span class="example">${definition["example"]}  </span>
                                        </div>
                                    </div>`
                    $("#definitions").append(html_temp)
                }
            }
        })
    }

다음과 같이해준다!

 

pronunciation 과 example 값이 null일 경우 설정

if -else 문 이용

$("#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 id="definitions">
                                        <div style="padding:10px">
                                            <i>${definition["type"]}</i>
                                            <br>${definition["definition"]}<br>
                                        </div>
                                    </div>`
                    }
                    else {
                        html_temp = `<div id="definitions">
                                        <div style="padding:10px">
                                            <i>${definition["type"]}</i>
                                            <br>${definition["definition"]}<br>
                                            <span class="example">${definition["example"]}  </span>
                                        </div>
                                    </div>`
                    }
                    $("#definitions").append(html_temp)

jinja를 이용해서 문자받아서 끼워넣어서 단어 api이용하기

새로고침을 할때마다 기존에 placeholder  에 넣어둔 owl이 보이는데,

받아오고 채워넣는데 시간이 걸리기때문

글씨없이 데이터 나타나게 하면 이상하다고 느끼기때문에

한번 페이지를 띄우고 나서 바뀔일이 없는 부분에 대해서는 jinja2같은 템플릿을 이용해서

 SSR을 해주는게 좋다.

 

app.py

def detail(keyword):
# API에서 단어 뜻 찾아서 결과 html에 보내기
r = requests.get(f"https://owlbot.info/api/v4/dictionary/{keyword}", headers={"Authorization": "Token fc4c687f7f2bbaf3808c5499ec484799f01dc28a"})

result = r.json()
print(result)
return render_template("detail.html", word=keyword, result = result)

 

owl에서 보내주는 데이터 형식

 

 

큰 딕셔너리 안에 단어 자체를 word라는 키로 보내줌

{{word}}말고도 result["word"] or result.word 로도 찾을 수 있음.

 

crtl + D를 누르면 코드 한줄 그대로 복사가능

단어의 이름과, 발음 채워넣ㄱ

 <div class="container">
        <div class="d-flex justify-content-between align-items-end">
            <div>
                <h1 id="word" style="display: inline;">{{ result. word }}</h1>
                <h5 id="pronunciation" style="display: inline;">{{result.pronunciaton}}</h5>
            </div>
            <button id="btn-save" class="btn btn-outline-sparta btn-lg">
                <i class="fa fa-floppy-o" aria-hidden="true"></i>
            </button>
            <button id="btn-delete" class="btn btn-sparta btn-lg">
                <i class="fa fa-trash-o" aria-hidden="true"></i>
            </button>
        </div>

 

 

 

단어의 뜻을 채워넣음 

리스트는 result안에 definitions

<div id="definitions">
            {% for definition in result.definitions %}
            <div style="padding:10px">
                <i>{{ definition.type }}</i>
                <br>{{ definition.definition}}<br>
                <span class="example">{{ definition.example}}</span>

            </div>
            {% endfor %}
        </div>

발음이 None일때

{% if result.pronunciation != None %}
<h5 id="pronunciation" style="display: inline;">{{result.pronunciaton}}</h5>
{% endif %} 

 

예문이 None일때

{% if definition.example %}
<span class="example">{{ definition.example|safe}}</span>
{% endif %}

 

|safe

진자2는 태그무시하는 기능이있어서

태그 들어오면 우리가 태그를 태그 그대로 사용해줘라는 명령을 따로 내려줘야함

 

깨지는 글자들 안깨지게하는  

아스키 코드로 바꿀 수 없는 애들은 무시하라는 뜻

<span class="example">{{ definition.example.encode('ascii','ignore').decode('utf-8')|safe}}</span>

 


상세페이지 - 새단어/기존보유 단어 구분하기

없는단어 : 저장버튼

있는단어:  상세버튼

 

구분 : 검색창에서 검색을해서 url ? 물음표 해서 파라미터로 넘겨주어서 값에따라 버튼 나타나게 

app.py

@app.route('/detail/<keyword>')
def detail(keyword):
status_receive = request.args.get("status_give")
# API에서 단어 뜻 찾아서 결과 html에 보내기
r = requests.get(f"https://owlbot.info/api/v4/dictionary/{keyword}", headers={"Authorization": "Token fc4c687f7f2bbaf3808c5499ec484799f01dc28a"})

result = r.json()
print(result)
return render_template("detail.html", word=keyword, result = result,status = status_receive)

-----------------------------------------------------------------------------------------------------------------------------------

detail.html

{% if status == "new" %}
<button id="btn-save" class="btn btn-outline-sparta btn-lg">
<i class="fa fa-floppy-o" aria-hidden="true"></i>
</button>
{% else %}

<button id="btn-delete" class="btn btn-sparta btn-lg">
<i class="fa fa-trash-o" aria-hidden="true"></i>
</button>
{% endif %}

-----------------------------------------------------------------------------------------------------------------------------------

http://localhost:5000/detail/name?status_give=old

이면 삭제버튼, new라면 저장버튼


삭제, 저장 기능만들기

단어 - 뜻 한줄씩 db에저장

db에는 데이터들의 묶음인 컬렉션이 있고, 각각의 줄을 도큐먼트라고함 그 각각의 열에 해당하는 값을 필드라고.

@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_receive} 저장}'})

result 안에

  ㄴ word

  ㄴpronunciation

  ㄴdefinitions 리스트

       ㄴ  리스트안에 definition,type,emoji,~~

 

 

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"
            }
        });

save버튼을 누르면 함수호출

<button id="btn-save" class="btn btn-outline-sparta btn-lg" onclick = " save_word() ">

 

 

http://localhost:5000/detail/hello?status_give=new 

하면 저장버튼이 뜨고 

저장하면 삭제버튼 뜸

 

단어 삭제버튼만들기

단어만 있으면 됨

다른거 받을 필요 없음

 

```python
@app.route('/api/delete_word', methods=['POST'])
def delete_word():
    # 단어 삭제하기
    word_receive = request.form['word_give']
    db.words.delete_one({"word":word_receive})
    return jsonify({'result': 'success', 'msg': f'word "{word_receive}" deleted'})
```
function delete_word() {
    $.ajax({
        type: "POST",
        url: `/api/delete_word`,
        data: {
            word_give: '{{ word }}',
        },
        success: function (response) {
            alert(response["msg"])
            window.location.href = "/"
        }
    });
}

 

css파일을 따로 분리해주면 가져다가 쓸수있기때문에

detail.html에 넣어준 스타일 요소들을 css로분리한다음에 메인으로 넣어주기

 

static- > stylesheet

.wrap {
    background-color: RGBA(232, 52, 78, 0.2);
    min-height: 100vh;
    padding-bottom: 50px;
}

.banner {
    width: 100%;
    height: 200px;

    background-color: white;
    background-image: url('{{ url_for("static", filename="logo_red.png") }}');

    background-position: center;
    background-size: contain;
    background-repeat: no-repeat;

    cursor: pointer;
}

jinja템플릿은 html에서만 쓸수있는거라서 css로 banner하고wrap옮겨왔을때 

사진 url오류 가 뜸.

{{ url_for("static", filename="logo_red.png") }} ---> logo_red.png

 

detail.html <head>에 넣어주기

<link href='{{ url_for("static", filename="mystyle.css") }}' rel="stylesheet">

 

메인페이지에도 이러한 레이아웃과 배너가 적용되게 해보자

<link href='{{ url_for("static", filename="mystyle.css") }}' rel="stylesheet">

head에 넣어주고,

<div class = "wrap">
            <div class = "banner" onclick="window.location.href = '/' ">

            </div>
        </div>

 

 

한번에 적용이 잘 안될때

static파일들을 캐시로 저장해놔서 옛날정보를 읽어와서 적용이 바로 안되기때문에

ctrl + shift +R 눌러서 캐시 삭제하고 하면 바로바로 적용됨


메인페이지에 검색창만들기

 

아이콘 허용하는 링크도 붙여줘야함 detail에다가만 했으니깐

 <link href="//maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet">

 

검색창

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

검색창css 

<style>
.search-box {
    width: 70%;
    margin: 50px auto;
    max-width: 700px;
}
</style>

 

테이블

<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">
        <tr id="word-word">
            <td><a href="#">word</a></td>
            <td>a single distinct meaningful element of speech or writing, used with others (or
                sometimes
                alone) to form a sentence and typically shown with a space on either side when written
                or
                printed.
            </td>
        </tr>
        <tr id="word-dictionary">
            <td><a href="#">dictionary</a></td>
            <td>a book or electronic resource that lists the words of a language (typically in
                alphabetical
                order) and gives their meaning, or gives the equivalent words in a different language,
                often
                also providing information about pronunciation, origin, and
            </td>
        </tr>
        <tr id="word-name">
            <td><a href="#">name</a></td>
            <td>a word or set of words by which a person or thing is known, addressed, or referred to.
            </td>
        </tr>
    </tbody>
</table>

 

css

.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;
}

테이블 테두리 둥글게 만들어주는

 


테이블에 내 DB단어들불러오기

 

페이지를 한번띄우고 나면 테이블 자체 수정안하니까

서버쪽에서 jinja2로 렌더링해서 html을 보내주는

 

서버쪽부터

app.py

 

index.html을 띄워주는 함수에서DB에 있는 단어들을 읽어다가

렌더템플릿안에 넣어줘야함.

@app.route('/')
def main():
    # DB에서 저장된 단어 찾아서 HTML에 나타내기
    words = list(db.words.find({},{"_id":False}))
    return render_template("index.html",words = words)

_id : False인 이유

_id라고 하는게 몽고DB에서 자동으로 만들어주는 아이디값임.

자료형이 특이해서 얘가 들어있는 리스트를 렌더 템플릿안에 넣어주면 이해할 수없어서 에러가 남 그래서 id빼고 적어줘야함

 

 

app.py에서 넘어오는 형식

 

index.html에서 넘어온 words에서 word나열해주기

<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}}</td>
            {% endfor %}
        </tr>
        </tbody>

검색창에 검색기능만들기

 

내 단어장에 있는지 없는지 판단해서

있으면 그 단어를 목록에서 찾아 하이라이트 해주는 기능

없는단어이면 (사전api에 있을때의 경우에) 단어에 대한 페이지 보여주는 기능

 

index.html에 <script></script>만들어서 자바스트립트 써줌

근데 페이지검사로 보면, 따옴표에 해당하는 html코드가 들어가버림

js안에서 진짜 따옴표처럼 행동하는거지, 출력하는(보여지는)게 아니기때문에

진짜 데이터로 알려주려면

wods뒤에 |tojson 으로 작성

 

리스트에 저장되어있는 단어 저장

<script>
        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)
    </script>

콘솔 확인해봄


목록에 있는지 없는지 확인하기

 

버튼에 함수 호출 넣어주고

function find_word(){
            //버튼의 아이디값 받아와서 word라는 변수에 저장, jquery사용
            let word = $("#input-word").val()
            //word변수가 리스트에 있는값인지 확인
            if (word_list.includes(word)) {
                // 리스트에 있으면 하이라이트
                $(`#word-${word}`).addClass("highlight")
                //첫번째 요소를 찾아서 너무 길면 스크롤해서 들어오게 해라
                $(`#word-${word}`)[0].scrollIntoView()

            }else {
                //리스트에 없으면 새 단어를 위한 상세페이지로 이동
                window.location.href = `/detail/${word}?status_give=new`

            }
        }

cow검색했을때

highlight클래스가 적용된걸 볼 수 있음.

지금은 얘한테 아무 스타일 적용안해서 눈으로는 변화안보임

tr이아니라, td에 적용해야 색깔이 나타남

 

tr.highlight > td{
            background-color : #e8344e;
            color : white;
        }
        tr.highlight >td >a {
            color : white;
        }

배경빨강

글씨하양

근데 단어는 흰색이안됨, a태그라서

a태그는 자기만의 특별한 속성이 있어서 

 

요 검정색으로 나타내는 성질이 먼저 먹게됨

그래서 a태그는 따로 먹여줘야함.


아무것도 입력안하고 엔터를 눌렀을때 안된다고 알려주는기능

if (word = ""){
                alert("값을 입력해주세요!")
                return
            }

중복 색깔적용 해결하기

tr과 tr은 같은 tbody안에 있는데

tr = tbody의 자식태그

tbody =tr의 부모태그

같은 부모를 갖는 두개의 tr은 형제임

그걸 이용해서 다른 형제들한테 있는하이라이트 클래스 제거해줘야함.

$(`#word-${word}`).siblings().removeClass("highlight")

ㄹㅇ형제라고하네,,


대문자를 섞었을경우에도 같은 단어인걸 알 수있도록해주기

let word = $("#input-word").val().toLowerCase()

.toLowerCase() : 무조건 소문자로


사전api에 없는 단어일때 단어가 존재하지 않습니다. (말도안되는 단어일때)

@app.route('/detail/<keyword>')
def detail(keyword):
    status_receive = request.args.get("status_give")
    # API에서 단어 뜻 찾아서 결과 html에 보내기
    r = requests.get(f"https://owlbot.info/api/v4/dictionary/{keyword}", headers={"Authorization": "Token  fc4c687f7f2bbaf3808c5499ec484799f01dc28a"})
    # 요청을 보냈을때 결과가 원하는 형태가 아니면 다시 홈으로 돌려보내기
    if r.status_code != 200:
        return redirect("/")

# 요청을 보냈을때 결과가 원하는 형태가 아니면 다시 홈으로 돌려보내기
if r.status_code != 200:
return redirect("/")

or

return redirect(url_for("main")) -> 함수이름적은거임메인함수

 

 

메시지도 같이보내주기

return redirect(url_for("main", msg="단어가 이상하잖아용!"))

 

main에서 받아오고

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

index.html에서

<script>
console.log("{{ msg }}")

로 어떻게  msg가 오는지 찍어보기

 

ㅋㅋㅋㅋㅋㅋㅋㅋ새침떼기같네

정상적일때는 

 

None이므로, 이걸이용해서 조건문 사용

{% if msg %}
            alert("{{ msg }}")
        {% endif %}

og태그랑 favicon해보깅

favicon은 사이트 아이콘

static에 사진저장하기

<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">

이거 html에붙여넣기


예문 추가,삭제 기능 만들기 (숙제)

어느정도 추가하고, 얼추 비슷하게 만들었는데

예문 끌고와서 비교하는 부분은 진짜 모르겠어서 보고 했다.

app.py

from flask import Flask, render_template, request, jsonify, redirect, url_for
from pymongo import MongoClient
import requests

app = Flask(__name__)

client = MongoClient('3.35.169.34', 27017, username="test", password="test")
db = client.dbsparta_plus_week2

@app.route('/')
def main():
    msg = request.args.get("msg")

    # DB에서 저장된 단어 찾아서 HTML에 나타내기
    words = list(db.words.find({}, {"_id": False}))
    return render_template("index.html", words=words, msg=msg)

@app.route('/detail/<keyword>')
def detail(keyword):
    # API에서 단어 뜻 찾아서 결과 보내기
    status_receive = request.args.get("status_give", "old")
    r = requests.get(f"https://owlbot.info/api/v4/dictionary/{keyword}",
                     headers={"Authorization": "Token fc4c687f7f2bbaf3808c5499ec484799f01dc28a"})
    # 요청을 보냈을때 결과가 원하는 형태가 아니면 다시 홈으로 돌려보내기
    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'})

@app.route('/api/get_examples', methods=['GET'])
def get_exs():
    word_receive = request.args.get("word_give")
    result = list(db.examples.find({"word": word_receive}, {'_id': 0}))
    print(word_receive, len(result))

    return jsonify({'result': 'success', 'examples': result})

@app.route('/api/save_ex', methods=['POST'])
def save_ex():
    word_receive = request.form['word_give']
    example_receive = request.form['example_give']
    doc = {"word": word_receive, "example": example_receive}
    db.examples.insert_one(doc)
    return jsonify({'result': 'success', 'msg': f'example "{example_receive}" saved'})

@app.route('/api/delete_ex', methods=['POST'])
def delete_ex():
    word_receive = request.form['word_give']
    number_receive = int(request.form["number_give"])
    example = list(db.examples.find({"word": word_receive}))[number_receive]["example"]
    print(word_receive, example)
    db.examples.delete_one({"word": word_receive, "example": example})
    return jsonify({'result': 'success', 'msg': f'example #{number_receive} of "{word_receive}" deleted'})

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

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="해송이의 단어장"/>
    <meta property="og:description" content="이게 내가 만든 단어장이드아아앗!!"/>
    <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>

</head>
<style>


    .container {
        width: 80%;
        max-width: 800px;
        margin: 30px auto;
        padding: 20px;
        background-color: white;

        border: solid 1px gray;
        border-radius: 10px;
    }

    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()
        {% if status == "old" %}
            get_examples()
        {% endif %}

    })


    {#ajax이용#}

    function get_definitions() {
        $.ajax({
            type: "GET",
            url: `https://owlbot.info/api/v4/dictionary/${word}`,
            beforeSend: function (xhr) {
                xhr.setRequestHeader("Authorization", "Token fc4c687f7f2bbaf3808c5499ec484799f01dc28a")
            },
            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 id="definitions">
                                        <div style="padding:10px">
                                            <i>${definition["type"]}</i>
                                            <br>${definition["definition"]}<br>
                                        </div>
                                    </div>`
                    } else {
                        html_temp = `<div id="definitions">
                                        <div style="padding:10px">
                                            <i>${definition["type"]}</i>
                                            <br>${definition["definition"]}<br>
                                            <span class="example">${definition["example"]}  </span>
                                        </div>
                                    </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=old"
            }
        });
    }

    function delete_word() {
        $.ajax({
            type: "POST",
            url: `/api/delete_word`,
            data: {
                word_give: '{{ word }}',
            },
            success: function (response) {
                alert(response["msg"])
                window.location.href = "/"
            }
        });
    }

    function get_examples() {
        $("#example-list").empty()
        $.ajax({
            type: "GET",
            url: `/api/get_examples?word_give=${word}`,
            data: {},
            success: function (response) {
                let examples = response["examples"];
                for (let i = 0; i < examples.length; i++) {
                    let example = examples[i]["example"];
                    console.log(example)
                    let html_temp = `<li id="ex-${i}">${example}&nbsp;&nbsp;&nbsp;<a
                            href="javascript:delete_ex(${i})">delete</a></li>`
                    $("#example-list").append(html_temp)
                }
            }
        });
    }

    function add_ex() {
        let new_ex = $('#new-example').val();
        if (!new_ex.toLowerCase().includes(word.toLowerCase())) {
            alert(`the word '${word}' is not included.`);
            return;
        }
        console.log(new_ex)
        $.ajax({
            type: "POST",
            url: `/api/save_ex`,
            data: {
                word_give: word,
                example_give: new_ex
            },
            success: function (response) {
                get_examples();
                $('#new-example').val("");
            }
        });


    }


</script>
<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.pronunciaton }}</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>
    {% if status == "old" %}
        <div id="examples" class="container">
            <h3 style="text-align: center;margin-bottom:1rem">Write your own sentences!</h3>
            <ul id="example-list">
                <li id="ex-0">This sentence contains the word 'word'.&nbsp;&nbsp;&nbsp;<a
                        href="javascript:delete_ex(0)">delete</a></li>
                <li id="ex-1">I don't like using the MS Word program.&nbsp;&nbsp;&nbsp;<a
                        href="javascript:delete_ex(1)">delete</a></li>
            </ul>
            <div class="d-flex justify-content-between" style="margin-left:20px;">
                <input id="new-example" class="form-control form-control-sm" style="margin-right: 0.5rem">
                <button class="btn btn-outline-secondary btn-sm" onclick="add_ex()">add</button>
            </div>
        </div>
    {% endif %}
</div>

</body>
</html>

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;
        }

        tr.highlight > td {
            background-color: #e8344e;
            color: white;
        }

        tr.highlight a {
            color: white;
        }

        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;
        }
    </style>
    <script>
        {% 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"])
        }

        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').siblings().removeClass('highlight');
                $(`#word-${word}`).get(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>

mystyle.css

.wrap {
    background-color: RGBA(232, 52, 78, 0.2);
    min-height: 100vh;
    padding-bottom: 50px;
}

.banner {
    width: 100%;
    height: 200px;

    background-color: white;
    background-image: url('logo_red.png');

    background-position: center;
    background-size: contain;
    background-repeat: no-repeat;

    cursor: pointer;
}

서버 연동

 

728x90

'✍~2022 > WEB' 카테고리의 다른 글

웹개발+4주차  (0) 2021.08.01
3주차 개발일지~!  (0) 2021.07.26
WEB 개발+ / 1주차 필기, 개발일지  (0) 2021.07.12
5주차 필기/개발일지  (0) 2021.07.01
4주차 개발/필기일지  (0) 2021.07.01