[항해99][1주차] #1. JINJA2 ?

Hajun Song·2022년 6월 23일
0

항해99

목록 보기
4/8
post-thumbnail

[1주차] #1. JINJA2 ?

항해99 1주차가 시작되었다.
미니 프로젝트를 기획하며 가장 먼저 마주한 어려움은 프로젝트의 조건이었다.

  1. jinja2를 이용 할 것.
  2. JWT 방식으로 회원가입/로그인 기능을 구현 할 것.

물론 기획한 프로젝트의 기능들을 당장 구현 할 자신은 있었다.

기획해봐~~ for랑 if 덕지덕지 하면 돼~~
그려봐봐~~ 부트스트랩 쓰면 돼~~

그렇지만 처음 듣는 jinja2는 도대체 뭐지? 새로운 프레임 워크인가?
기능들을 다 구현하고 찾아봐도 되나? 걱정이 앞섰다.


이번 미니 프로젝트를 진행하며 수도 없이 많은 구글링을 하며 느낀 점이 있다.
개발자들이라는 사람들은 다들 정리를 엄청엄청 잘 해놓는다.
그것이 남을 위해서든, 하루지나 까먹을 나 자신을 위해서든 잘 해놓는다.

나도 항해, 정글 출신 개발자들의 정리를 보고 감을 잡았다.
오늘은 내가 그 바통을 내밀 준비를 할 차례이다.

human knowledge belongs to the world!!!


💡 JINJA2 ?

flask 에서 제공하는 템플릿 언어?

서버에서 받아온 정보를 효과적으로 보여줄 중간 매체
템플릿?? 서식을 만들어두는 언어...?
뭐라는지는 아직 모르겠지만 페이지를 하나하나 직접 만들지 않아도 된다는 말씀..!

{{ }} 와 {% %}

공식적인 설명은 어떨지 모르겠으나 jinja2의 표현에는 크게 두가지 방법이 있다.
참조와 기능, 정보와 가공, 변수와 로직 적당한 표현이 생각나지 않는다.
바로 {{ }}와 {% %} 이다.

{{ }}

🔍 {{ }} 참조?, 정보? 변수?
{{ }}는 서버에서 페이지를 렌더링 할 때 변수(정보)를 함께 보내어 언제든지 사용 할 수 있게 해준다.

jinja2의 기본 사용법을 위한 세팅은 아래와 같다.

<!--app.py-->

@app.route('/login')   		
def login():				
    # 팀에 관한 db 불러오기
    all_teams = list(db.teams.find({}, {'_id': False}))

    return render_template('login.html', all_teams=all_teams)

포인트는 아래 한 줄이다.

return render_template('랜더링 할 html', 브라우저로 전달되는 변수이름=내용)

이 구문을 사용하면 랜더링 할 페이지 html 즉 login.html에서 변수 all_teams 을 사용 할 수 있게 된다.

login.html을 작성하는 동안 all_teams을 사용하는 방법은 {{all_teams}}이다.

물론 아래와 같이 병렬하여 여러 정보를 전달 할 수도 있다.

return render_template('랜더링 할 html',item1=item1,item2=item2,item3=item3)

예문은 아래와 같다.

#app.py
...
@app.route('/')   		
def login():				
    
    myname='HAYUN'
    return render_template('index.html', myname=myname)
...
<!--index.html-->

<html> 
  <head>
    <title>Jinja</title>
  </head>
  <body>
    <p>{{myname}}</p>
  </body>
</html>
<!--결과-->

<html> 
  <head>
    <title>Jinja</title>
  </head>
  <body>
    <p>HAYUN</p>
  </body>
</html>

✨ 웹 페이지를 결과로 보여주는 것이 아니라, index.html을 그려주는 것이다. 매우 다르다.

💡 TIP for {{ }}

{{ }} 안에 뭐가 들어갈지 모른다. 그렇기에 이를 다룰 수 있는 방법이 있다.
{{ name | x }} x의 종류는 아래와 같다.

  • safe - html tag를 정상 적용
  • striptags - html tag를 제거
  • lower - 소문자로 만듬 //
  • upper -대문자로 만듬
  • title - 단어의 첫 글자들을 대문자로 만듬
  • trim - 마지막 공백을 제거

여기까지 알았을 땐 뭔가 아쉬웠다. 이 기능으론 페이지에서 서버에 GET 요청을 하고 이에 서버가 db를 조회해서 전달하는 것이랑 차이를 못 느꼈다. 결론적으론 응용성 측면에서 차이가 크다는 생각에 이 기능을 다음과 같이 정리를 했다.

  1. 페이지 랜더링 때 부터 원하는 정보를 사용 할 수 있다.
  2. 정보를 사용 하고 싶을 때 서버에 계속 요청할 필요가 없다.

{% %}

🔍{% %} 기능?, 가공?
{% %}의 대표적인 강한 기능은 html에서 for if 구문의 사용이다.

for 사용법

기본적으로 python과 같으나 닫는 표현이 반드시 필요하다.
{% for x in name %}
{% endfor%}

if 사용법

기본적으로 python과 같으나 닫는 표현이 반드시 필요하다.
{% if x ==3 %}
{% endif%}

💡 {{ }}를 더불어 같이 사용 할 경우 그 위력은 배가 된다.

예문은 아래와 같다.

#app.py
...
@app.route('/')   		
def login():				
   
   myname=['HAJUN','JINSU','HANEUL','BOB']
   return render_template('index.html', myname=myname)
...
<!--index.html-->

<html> 
 <head>
   <title>Jinja</title>
 </head>
 <body>
   <ul>
     {% for x in myname %}
     <li>
     	{{x}}
     </li>
     {% endfor %}
   </ul>
 </body>
</html>
<!--결과-->

<html> 
  <head>
    <title>Jinja</title>
  </head>
  <body>
    <ul>
      <li>HAJUN</li>
      <li>JINSU</li>
      <li>HANEUL</li>
      <li>BOB</li>
    </ul>
  </body>
</html>

✨ 웹 페이지를 결과로 보여주는 것이 아니라, index.html을 그려주는 것이다. 매우 다르다.


끝이 아니다.

include or extends

jinja2의 HTML 렌더링에 사용되는 대표적인 로직은 include , extends 두가지가 있다.

include

include는 HTML을 부분부분 나누어 재사용 가능한 형태로 가공하는 기능이다.

예시로 메인 페이지 index.html 이 아래와 같이 있다.


<!--index.html-->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello world!</title>
</head>
<body>
    <h1>my body!</h1>
</body>
</html>

이때 head 쪽 내용 중 서비스에 공통적인 사용이 필요한 Font, Script, css 등을 재사용 하기 위해 include 기능을 사용하고자 한다면 head.html을 새로 만들어 html의 head 부분을 작성해주면 된다.


<!--head.html-->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello world!</title>
</head>

이러면 각각의 페이지를 만들때 새로 쓸 필요 없이 아래의 명령어를 원하는 곳에 붙이는 것으로 가져다 쓸 수 있다.

include 사용법

{% include '파일명.html'%}

include를 넣어 만든 index.html은 아래와 같다.

<!--index.html('head.html' include 후)-->

{% include 'head.html'%}
<body>
    <h1>my body!</h1>
</body>
</html>

이와같이 index 파일을 보다 간결하게 가독성 있게 만들 수 있고, navbar, footer(copyright) 등 을 원하는 모든 페이지에 가져다 붙이는 등 손쉽게 모듈화가 가능해 유지보수에 이점이 있다.

extends

extends는 HTML의 한 부분을 상황에 맞게 바꿔쓸 수 있게 만드는 기능이다.
PPT 작성 시 인터넷에서 템플릿을 다운받아 그 안의 내용만 바꾸는 기능과 유사하다.

extends 사용법

{% block 이름 %}
상황별로 바꾸고 싶은 내용
{% endblock %}

... 그냥 봐선 모르겠다.
예시로 아래 app.py와 메인 페이지 index.html이 있다.

#app.py
...
@app.route('/<name>')	#주소의 name을 불러와서
def name_site(name):	#함수에 name을 넣어 
    return render_template('name.html',name=name)
    #jinja를 이용해 사용 할 수 있다.
    #💡 index.html을 랜더하는 것이 아니다. 이하 내용 참고.
...
<!--index.html-->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    {% block title %}			<!-- title을 바꾸고 싶으면 -->
    <title>hello world!</title>
    {% end block %}				<!-- 꼭 닫기 -->
</head>
<body>
	{% block h1 %}				<!-- h1도 바꾸고 싶으면 -->
    <h1>my body!</h1>
    {% endblock %}				<!--꼭 닫기 -->
</body>
</html>

이때, index.html의 내용 중 사이트 별로 다르게 표현이 필요한 title과 h1 등이 있어서 extends 기능을 사용하고자 한다면 name.html을 새로 만들어 extends 구문을 작성해주면 된다.

{% extends 'index.html' %}
<!--name.html을 랜더링 했지만 name.html의 기본 내용 틀을 index.html로 설정한다.-->

{% block title %}
<title>I'm {{ name | upper }}</title>
{%endblock%}

{% block title %}
<title>I'm {{ name | title }}</title>
{%endblock%}

/dahyun 경로로 접근 시 @app.route('/<name>')에 따라
/dahyun으로 이동 및 def name_site(dahyun) 이 작동한다.
return render_template('name.html',name=name)에 따라
랜더링 될때 name 정보가 함께 넘어가 {{ }}를 이용하여 사용 할 수 있게 된다.

<!--결과 name.html-->
<!--name.html을 불러왔으나 extends 구문을 통해 index.html을 베이스로 설정해둔 변경사항을 적용한다.-->


<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>I'm DAHYUN</title>
</head>
<body>
    <h1>I'm Dahyun</h1>
</body>
</html>

미니 프로젝트를 위해 jinja2를 사용하고...

잘 썼다. 사실 페이지 별 내용이 아닌 구조의 변화를 바라지 않는 이상 extends가 얼마나 쓰일지는 잘 모르겠다. 페이지마다 변화를 원하면 그냥 경로에 따라 다르게 들어오는 값을 {{ }}를 이용해 넣으면 되기 때문이다.

이번 미니 프로젝트를 통해서도 extends를 많이 쓰기 보다는 include를 이용해 모든 페이지에 중첩된 부분들(head, navbar 등)을 index.html에서 줄이는 페이지의 모듈화 용도로 많이 사용했다.
이때 html 파일이 많아지면서 작명의 중요성을 느꼈다.

물론 가장 공이 컸던 부분은 미니 프로젝트를 위해 우리가 필요했던 20개의 프리미어리그 팀 사이트들을 간편하고 쉽게 만들 수 있었던 것이 아닐까 싶다.

/team/everton을 치고 들어가면 서버에서 지지고 복고 db 따와서
이름이 EVERTON Team Page인 페이지를 만들어준다.
메인 페이지에 각 팀 링크for 문으로 넣어주기만 하면 OK

미니 프로젝트 app.py
...
# 팀 사이트 랜더링
@app.route('/team/<teamtitle>')
def team_temp(teamtitle):
  # 필요 자료형으로 치환 ('-' 제거 등)
  teamtitle = str(teamtitle).replace('-', ' ')

  # 팀에 관한 db 불러오기
  team = db.teams.find_one({'name': teamtitle})
  if team:  # 주소가 올바른 팀 이름이면(데이터베이스에 있는 팀 이름이면!)
      # 팀 경기결과 불러오기
      ...
      ### 뉴스 크롤링

      ...  
      return render_template('teamTemp.html',
                             teamtitle=teamtitle,
                             teamlogo=team['logo'],
                             teamname=team['name'],
                             teambbc=team['bbc'],
                             # 최근 경기 결과
                             blue_name=blue_name,
                             blue_score=blue_score,
                             red_name=red_name,
                             red_score=red_score,
                             # 다음 경기 계획
                             plan_blue_name=plan_blue_name,
                             plan_red_name=plan_red_name,
                             plan_month=plan_month,
                             plan_date=plan_date,
                             plan_day=plan_day,
                             plan_time=plan_time,
                             # 팀 뉴스
                             news_dict=news_dict
                             )
  else:
      return jsonify({'msg': '올바르지 않은 접근방식입니다.'})
...
미니 프로젝트 team.html
<html lang="en" xmlns="http://www.w3.org/1999/html">
<head>
    <meta charset="UTF-8">
    <title>{{ teamtitle | upper }} Team Page</title>
    {% include 'head.html' %}
    {% include 'head_script.html' %}
</head>
<body>
<!-- Nav Bar -->
{% include 'navbar.html' %}
<div class="padding_container">
    <section id="team-intro">
        <!-- header (team_logo,team_name atc...) -->
        {% include 'header.html' %}
    </section>
    <section id="team-game">
        <!-- game (game_result,game_plan atc...) -->
        {% include 'game.html' %}
    </section>
    <section id="team-tabbar">
        <!--tabbar (news and notice tab switch bar) -->
        {% include 'tabbar.html' %}
    </section>
    <section id="team-news">
        <!--news (news from bbc) -->
        {% include 'news.html' %}
    </section>
    <section id="team-notice">
        <!--notice (login to use) -->
        {% include 'notice.html' %}
    </section>
</div>
</body>
</html>
  
profile
일단 똥을 싸라, 그리고 박수칠 때 까지 닦아라.

0개의 댓글