나만의 단어장

swb·2021년 8월 27일
1

1. 플라스크로 멀티페이지 사이트 만들기 - 기초

  1. 메인 페이지로 돌아가는 방법
onclick = window.location.href = "/"
  1. jinja2 템플릿 언어 사용하기
  • 서버에서 값을 보내준다.
  • html 파일에서 이 값이 들어갈 자리 표시.
    {{ 값 }}

2. 플라스크로 멀티페이지 사이트 만들기 - 응용

  1. 렌더링할 html에 정보 보내기
return render_template("index.html", name=name, rows=rows)
  1. 첫번째 정보를 태그로 만들기
<li>{{ rows[0].MSRSTE_NM }}: {{ rows[0].IDEX_MVL }}</li>
  1. 변수에 저장하기
{% set gu_name = rows[0].MSRSTE_NM %}
{% set gu_mise = rows[0].IDEX_MVL %}
<li>{{ gu_name }}: {{ gu_mise }}</li>
  1. 모든 정보에 대해서 태그 만들기
{% for row in rows %}
    {% set gu_name = row.MSRSTE_NM %}
    {% set gu_mise = row.IDEX_MVL %}
    <li>{{ gu_name }}: {{ gu_mise }}</li>
{% endfor %}
  1. if 문 활용
{% if gu_mise >= 50 %}
    <li>{{ gu_name }}: {{ gu_mise }}</li>
{% endif %}
  1. URL의 일부를 변수로 받기
@app.route('/detail/<keyword>')
def detail(keyword):
    return render_template("detail.html", word=keyword)

3. 사전 API 사용하기

  1. Owlbot이라는 Open API에서 영단어의 발음, 뜻, 예문을 받아온다.
https://owlbot.info/
  1. API 키 신청하여 토큰을 받는다.
  2. 파이선으로 API에 요청 보내기.
r = requests.get("https://owlbot.info/api/v4/dictionary/owl", headers={"Authorization": "Token [내토큰]"})
result = r.json()
print(result)
  1. Ajax로 요청 보내기
$.ajax({
    type: "GET",
    url: "https://owlbot.info/api/v4/dictionary/owl",
    beforeSend: function (xhr) {
        xhr.setRequestHeader("Authorization", "Token [내토큰]");
    },
    data: {},b
    error: function (xhr, status, error) {
        alert("에러 발생!");
    },
    success: function (response) {
        console.log(response)
    }
})

4. 프로젝트 세팅

  1. app.py 준비하기
  2. index.html, detail.html 준비하기
  3. 배너 이미지 준비하기

5. 상세 페이지 전체 모습 만들기

  1. 배경과 배너 넣기
  2. 단어 뜻 박스 만들기
  3. 아이콘 삽입하기
  • 아이콘은 Font Awesome이라는 곳에서 가져와 씀.
https://fontawesome.com/v4.7.0/

6. 상세 페이지 - Ajax로 단어 뜻 가져오기

  1. html에서 단어 뜻 보여주기 - ajax 이용
    1) 우선 ajax를 이용해서 단어 뜻을 가져와 넣어본다.
    [Owlbot API 요청 Ajax]
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)
        }
    })
}

2) API에서 받은 값들을 해당하는 태그에 넣어준다.

$("#word").text(response["word"])
$("#pronunciation").text(`/${response["pronunciation"]}/`)
$("#definitions").empty()
let definitions = response["definitions"]
for (let i=0;i<definitions.length;i++) {
    let definition = definitions[i]
    let 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)
}

3) 발음이 null일 경우 빈 텍스트를 넣어준다.

if (response["pronunciation"]==null) {
    $("#pronunciation").text("")
} else {
    $("#pronunciation").text(`/${response["pronunciation"]}/`)
}

4) 예문이 null일 경우 예외처리를 해준다.

let html_temp = ``
if (definition["example"]!=null) {
    html_temp = `<div style="padding:10px">
                    <i>${definition["type"]}</i>
                    <br>${definition["definition"]}<br>
                    <span class="example">${definition["example"]}</span>
                </div>`
} else {
    html_temp = `<div style="padding:10px">
                    <i>${definition["type"]}</i>
                    <br>${definition["definition"]}<br>
                </div>`
}

$("#definitions").append(html_temp)

7. 상세 페이지 - jinja2로 뜻 가져오기

  1. html에서 단어 뜻 보여주기 - jinja2 이용
    1) 우선 app.py에서 API에 요청을 보내 받은 응답을 보내준다.
    [Owlbot API 요청 Flask]
r = requests.get(f"https://owlbot.info/api/v4/dictionary/{keyword}", headers={"Authorization": "Token [내토큰]"})
result = r.json()
print(result)

2) html에서 결과가 들어가야할 부분을 표시해준다.
3) 발음이 있는 경우에만 보여주도록 예외처리를 해준다.

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

4) 예문이 있는 경우에만 보여주도록 예외처리를 해준다.

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

5) 예문에 HTML 태그 쓰는 것을 허용해준다.

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

6) 정의와 예문에서 깨진 글자를 없앤다.

<br>{{ definition.definition.encode('ascii', 'ignore').decode('utf-8') }}<br>
{% if definition.example %}
    <span class="example">{{ definition.example.encode('ascii', 'ignore').decode('utf-8') }}</span>
{% endif %}

8. 상세 페이지 - 새 단어/기존 단어 구분하기

  1. 새 단어 인지 기존에 있던 단어인지에 따라 보여주는 버튼이 달라야 한다. 우선 서버에서 status_give 라는 이름으로 온 파라미터를 다시 status 라는 이름으로 템플릿에 보내준다.
status_receive = request.args.get("status_give")
return render_template("detail.html", word=keyword, result=result, status=status_receive)
  1. status_give라는 파라미터를 주지 않을 경우를 대비해, 기본값을 "new"로 준다.
status_receive = request.args.get("status_give", "new")
  1. jinja2를 이용하여 사오항에 맞는 버튼이 보이도록 한다.
{% if status=="new" %}
    <button id="btn-save" class="btn btn-outline-sparta btn-lg" onclick="save_word()">
        <i class="fa fa-floppy-o"></i>
    </button>
{% else %}
    <button id="btn-delete" class="btn btn-sparta btn-lg" onclick="delete_word()">
        <i class="fa fa-trash-o"></i>
    </button>
{% endif %}
  1. 상세 페이지 - 저장 & 삭제 기능 만들기
    1.단어 저장 기능 만들기
    1) 목록 페이지에서는 단어 당 뜻을 하나만 보여줄 것이기 때문에 단어와 첫 번째 정의만 POST 요청으로 보내고, 서버에서 단어와 뜻을 받아 words 컬렉션에 저장한다.
@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'})

2) 클라이언트에서는 단어와 첫 번째 정의만 POST 요청으로 보내준다. 단어 저장에 성공하면 얼럿을 띄운 후, status=old로 바뀐 페이지를 띄워준다. 저장 버튼에 onclick=save_word()로 연결해준다.
[save_word()시작코드)

function save_word() {
    $.ajax({
        type: "POST",
        url: `/api/save_word`,
        data: {},
        success: function (response) {
           alert(response["msg"])
        }
    });
}
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"
        }
    });
}
  1. 단어 삭제 기능 만들기
    1) 단어를 삭제할 때는 단어만 있으면 되므로 POST 요청으로 단어를 보내주고, 서버에서는 해당 단어를 찾아 삭제해준다.
@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'})

2) 클라이언트에서는 단어를 보내주고, 단어 삭제에 성공하면 더이상 보여줄 정보가 없으므로 얼럿을 띄운 후 메인 페이지로 이동한다.
[delete_word()] 시작 코드

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

9. 목록 페이지 - 전체 모습 만들기

  1. CSS 파일 분리하기
  2. 검색창과 테이블 만들기

10. 목록 페이지 - 단어 목록 가져오기

  1. jinja2로 단어 목록 테이블 채우기
    1) 이제 실제로 DB에서 단어 목록을 가져와 테이블로 채운다.
    2) app.py에서는 words 컬렉션의 단어들을 가져와 넘겨준다.
@app.route('/')
def main():
    # DB에서 저장된 단어 찾아서 HTML에 나타내기
    words = list(db.words.find({}, {"_id": False}))
    return render_template("index.html", words=words)

3) index.html에서는 각 단어마다 테이블의 한 줄이 되도록 넣어준다.

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

11. 목록 페이지 - 검색 기능 만들기

  1. 단어 검색 기능 만들기
    1) 단어를 검색했을 때 이미 저장된 단어인지 알기 위해서 단어 리스트를 만든다.
let words = {{ words|tojson }};
let word_list = [];
for (let i = 0; i < words.length; i++) {
    word_list.push(words[i]["word"])
}

2) 단어를 검색했을 때 단어 리스트에 있는 경우에는 행을 하이라이트하고, 없는 단어 일 때는 단어 상세페이지로 넘어가는 기능을 만든다.

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}`)[0].scrollIntoView();
    } else {
				// 리스트에 없으면 상세 페이지로
        window.location.href = `/detail/${word}?status_give=new`
    }
}

12. 목록 페이지 - 사전에 없는 단어일 때

  1. 단어가 존재하지 않을 때 기능 만들기
    1) 주소에 단어가 아닌 것을 넣었을 때, 사전 API에서 단어를 찾을 수 없기 때문에 에러가 난다. 이 때 에러를 보여주지 않고 단어 목록 페이지로 리다이렉팅시킨다.
    2) 값을 잘 받아왔을 때 상태 코드가 200이므로 200이 아닐 때 main으로 리다이렉팅 시킨다.
if r.status_code != 200:
        return redirect(url_for("main"))

3) 단어 찾기 실패 얼럿을 띄우려면 redirect()에 메시지를 같이 전달한다.

url_for("main", msg="Word not found in dictionary; Try another word")

4) main()에서 메시지를 받아 템플릿에 같이 보내준다.

@app.route('/')
def main():
    # DB에서 저장된 단어 찾아서 HTML에 나타내기
    msg = request.args.get("msg")
    return render_template("index.html", words=words, msg=msg)

5) index.html에서 msg가 있을 때 해당 메시지로 얼럿을 띄운다.

{% if msg %}
    alert("{{ msg }}")
{% endif %}
  1. og태그, favicon넣기
profile
개발 시작

0개의 댓글