Today I Learned

나만의 단어장 만들기 2 - Jinja2

개발자 김혜린 2021. 10. 8. 04:55
        <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>
        </tr>
        {% endfor %}
        </tbody>

배경과 배너 등 디자인 요소가 겹치므로 CSS 파일을 분리하여 링크로 넣어주면 같은 CSS를 적용해줄 수 있음!

static 폴더에 mystyle.css 파일을 만들고 공통 요소에 대한 CSS를 잘라내어 붙여넣는다

배너 이미지는 같은 폴더에 있으니 바꿔주깅

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

 

index, detail 두 html 파일안에 아래 코드를 넣는다.

의미는 진자 템플릿 언어를 이용해 static 폴더 안에 mystyle.css에 해당하는 url을 만들어줘! ㄹㅏ고 하는 url_for 사용

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

 

DB에 저장된 단어 찾아서 HTML에 나타내기

_id가 mongoDB에서 자동으로 넣어주는 값인데 render_template에 넣어주면 이해를 못해서 에러가 나기때문에

_id에 해당하는 열은 꼭 빼주고 넣어줘야함

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

 

우선 tbody 안에 tr을 반복할 것이기 때문에

        <tbody id="tbody-box">
        {% for word in words %}
        <tr id="word-word">
            <td><a href="#">word</a></td>
            <td></td>
        </tr>
        {% endfor %}
        </tbody>

 

app.py에서 넘어오는 데이터의 형태

 

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

이제 리스트에 있는 단어 불러와보자!

스크립트 안에, words를 json형태로 받고 반복문으로 불러온다

(단어를 검색했을 때 이미 저장된 단어인지 알기 위해서 있는 단어 리스트)

        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() //input-word에 값을 받아주면 word에 저장됨
            if (word_list.includes(word)) { //word_list 안에 word가 있다면
                //리스트에 있으면 하이라이트
                $(`#word-${word}`).addClass("highlight")
                $(`#word-${word}`)[0].scrollIntoView() //#word-${word} 에 맞는 첫번째 요소를 찾아 스크롤하라
            }else{ //리스트에 없으면 새 단어 위한 상세페이지로
                window.location.href=`/detail/${word}?status_give=new`
            }
        }

 

하이라이트 빨강색 주기

tr 안에 있는 td 안에다가 스타일을 주라는 의미

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

 

단어는 a태그라 검정색이 되네..

그래서 하얀색 되도록 또 스타일 만들어줌

        tr.highlight > td > a {
            color: white;
        }

 

아무것도 입력 안하고 검색했을때를 위해 코드 추가

        function find_word(){
            let word=$("#input-word").val() //input-word에 값을 받아주면 word에 저장됨
            if (word==""){ // ******아무것도 입력 안하고 검색했을 때
                alert("값을 입력해주세요!")
                return
            }
            if (word_list.includes(word)) { //word_list 안에 word가 있다면
                //리스트에 있으면 하이라이트
                $(`#word-${word}`).addClass("highlight")
                $(`#word-${word}`)[0].scrollIntoView() //#word-${word} 에 맞는 첫번째 요소를 찾아 스크롤하라
            }else{ //리스트에 없으면 새 단어 위한 상세페이지로
                window.location.href=`/detail/${word}?status_give=new`
            }
        }

 

리스트에 검색했을 때 빨간색이 되는 것이 계속 남아있다.

tbody는 td들의 부모이고, td들은 형제이기 때문에

td들 중 한명이 검색됐을 때 다른 애들은 하이라이트 기능이 없어지도록 해보장

function find_word()에다가,

형제들을 찾아서 하이라이트 클래스를 없애줘 라는 의미의 코드 추가!

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

 

대문자와 소문자는 같은 단어야! 라고 인식하도록 해보장

무조건 소문자로 input-word를 받자!

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

요상한 단어를 검색했을 때, 그냥 홈으로 돌아오도록 하게 하자

redirect는 현재 요청된 연결을 다른 주소로 연결,

(값을 잘 받아왔을 때 상태 코드가 200이므로 200이 아닐 때 main으로 리다이렉팅)

render_template는 템플릿을 렌더링하는 것

 

@app.route('/detail/<keyword>') #주소 URL의 일부(앞부분만)받아
def detail(keyword):
    status_receive=request.args.get("status_give")
    #keyword 라는 변수로 저장을 해서 요청을 보내는 URL뒤에 넣어준 뒤, header 정보 안에 내 토큰을 넣어준다
    r = requests.get(f"https://owlbot.info/api/v4/dictionary/{keyword}", headers={"Authorization": "Token ed4c16e8cab27f9cf2587dcba3c60d9a2a89a0ee"})

    if r.status_code!=200:
        return redirect(url_for("main", msg="단어가 이상합니다!")) #현재 요청된 연결을 특정 주소로 재연결

    result = r.json()
    print(result)
    return render_template("detail.html", word=keyword,result=result,status=status_receive) #detail/ 뒤에 오는 단어를 word로 보냄

 

detail에서 온 메시지를(status) alert로

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

 

완성도를 위해 og태그를 넣자!(공유했을 때 예쁜 이미지가 나오게..)

favicon도 넣어보자~(상단 탭의 왼쪽 모양)

<title>아래에다가 아래 코드 붙여넣고,

파비콘 이미지와 og 이미지 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='lee.jpg') }}"/>
    <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">