본문 바로가기

Python

Flask 6 : 템플릿

https://flask.palletsprojects.com/en/1.1.x/tutorial/templates/


템플릿 Templates

지금까지는 웹사이트에서 이용할 사용자 인증 관련 기능을 개발했습니다. 하지만 이들 URL에 접속하려고 하면 TemplateNotFound 라는 에러메시지가 뜹니다. 이는 사용자 인증 관련 뷰가 render_template() 이라는 함수를 호출하지만 아직 템플릿을 작성하지 않았기 때문이죠. flaskr 패키지에서는 템플릿 파일들을 templates 디렉터리에 저장할 것입니다. 

템플릿은 정적인 데이터 뿐 아니라 placeholder를 이용해 표시되는 동적인 데이터를 함께 담고있는 파일입니다. 템플릿은 데이터와 결합해 최종적인 화면을 생성합니다. Flask는 템플릿을 화면에 뿌려주기 위해 Jinja 라는 템플릿 라이브러리를 사용합니다.

Jinja는 autoescape, 즉 사용자가 입력한 문자가 기존 html 코드와 뒤섞여서 화면을 깨지게 만드는 것을 방지하는 기능을 탑재하고 있습니다. 

Jinja는 파이썬과 매우 유사한 형식을 갖습니다. 템플릿 내에서 {{ 와 }} 로 둘러쌓인 부분은 출력문 삽입을 위해 사용되고,  {% 와 %} 로 둘러쌓인 부분은 if 나 for 와 같은 제어문을 삽입할 때 사용됩니다. 파이썬과 다른 부분은 들여쓰기를 통해 for 나 if 에 속한 절이 구분되지 않고 시작과 끝을 표시하는 태그를 이용한다는 점 입니다.

베이스 레이아웃 

대게 웹사이트의 각 페이지는 본문을 제외하면 동일한 헤더와 풋터를 갖는 단일 레이아웃으로 표현됩니다. 베이스 레이아웃을 이용해 각 템플릿마다 전체 레이아웃을 일일히 작성하는 대신, 중복되는 부분을 재활용 할 수 있습니다.

flaskr/templates/base.html
<!doctype html>
<title>{% block title %}{% endblock %} - Flaskr</title>
<link rel="stylesheet" href="{{ url_for('static', filename='style.css') }}">
<nav>
  <h1>Flaskr</h1>
  <ul>
    {% if g.user %}
      <li><span>{{ g.user['username'] }}</span>
      <li><a href="{{ url_for('auth.logout') }}">Log Out</a>
    {% else %}
      <li><a href="{{ url_for('auth.register') }}">Register</a>
      <li><a href="{{ url_for('auth.login') }}">Log In</a>
    {% endif %}
  </ul>
</nav>
<section class="content">
  <header>
    {% block header %}{% endblock %}
  </header>
  {% for message in get_flashed_messages() %}
    <div class="flash">{{ message }}</div>
  {% endfor %}
  {% block content %}{% endblock %}
</section>

g.user 정보의 존재 여부에 따라 username과 logout 링크가 표시될지, register와 log in 링크가 표시될지 결정됩니다. url_for() 역시 g.user 정보에 따라 자동으로 생성됩니다.

페이지 타이틀과 본문 사이에 템플릿은 루프를 돌면서 get_flashed_messages() 가 생성하는 메시지를 뿌려줍니다.

템플릿들이 공유하는 블록들은 다음 세 개 입니다:

  1. {% block title %} 블록은 브라우저 탭에 표시될 페이지 제목을 출력합니다.

  2. {% block header %} 는 웹페이지상에 표시되는 페이지 제목을 출력합니다.

  3. {% block content %} 는 각 페이지의 본문이 표시되는 부분입니다.

베이스 템플릿은 템플릿 디렉토리 안에 위치합니다. 다른 파일들과 함께 유기적으로 유지하기 위해 블루프린트를 위한 템플릿은 블루프린트와 같은 이름의 디렉토리들에 저장됩니다.


Register : 신규 사용자 등록

flaskr/templates/auth/register.html
{% extends 'base.html' %}

{% block header %}
  <h1>{% block title %}Register{% endblock %}</h1>
{% endblock %}

{% block content %}
  <form method="post">
    <label for="username">Username</label>
    <input name="username" id="username" required>
    <label for="password">Password</label>
    <input type="password" name="password" id="password" required>
    <input type="submit" value="Register">
  </form>
{% endblock %}

{% extends 'base.html' %} 는 Jinja 라이브러리가 이 부분에 베이스 템플릿을 가져와 쓰도록 지정합니다.  출력이 될 모든 컨텐츠는 {% 블록 %} 내에 지정되고, 베이스 템플릿 위에 표시됩니다.

여기에서는 {% block title %} 이 {% block header %} 내에 위치하고 있습니다. 이렇게 함으로써, 타이틀을 두 번 코딩해주는 수고를 덜 수 있습니다.

input 태그들은 required 라는 속성을 포함하고 있습니다. 이렇게 하면 브라우저는 이 필드들에 값이 채워질 때 까지 submit을 하지 않습니다. 일부 구버전 브라우저에서는 이 속성이 작동하지 않을 수 있습니다. 

Log In : 로그인

이 템플릿은 제목과 submit 버튼을 제외하면 register와 동일합니다.

flaskr/templates/auth/login.html
{% extends 'base.html' %}

{% block header %}
  <h1>{% block title %}Log In{% endblock %}</h1>
{% endblock %}

{% block content %}
  <form method="post">
    <label for="username">Username</label>
    <input name="username" id="username" required>
    <label for="password">Password</label>
    <input type="password" name="password" id="password" required>
    <input type="submit" value="Log In">
  </form>
{% endblock %}

Register A User : 사용자 등록하기

이제 템플릿이 준비되었으니, 사용자 등록을 할 수 있습니다. 웹서버가 기동중인지 확인하세요. 기동중이 아니라면 터미널에서 flask run 명령어를 입력해 구동시킵니다. 그리고 브라우저에 http://127.0.0.1:5000/auth/register 를 입력해 사용자를 등록하러 갑니다.

양식을 다 입력하지 않고 "Register" 버튼을 눌러보고 에러메시지가 정상적으로 출력되는지 확인해보세요. 

username 과 password 를 정상적으로 입력하면 등록이 완료되고 로그인 페이지로 안내됩니다. 정상적으로 로그인을 하게되면 에러 메시지가 출력될거에요. 아직 index 페이지를 만들지 않아서 그래요.


다음 : 정적 파일 Static Files.


'Python' 카테고리의 다른 글

Flask 8 : 블로그 블루프린트  (0) 2019.10.03
Flask 7 : 정적 파일  (0) 2019.09.08
Flask 5 : 블루프린트와 뷰  (0) 2019.08.28
Flask 4 : DB 구축  (1) 2019.08.28
Flask 3 : 어플리케이션 설치  (0) 2019.08.28