2017. 10. 31.

[Python] Flask - Template과 웹 템플릿 시스템(Web Template System)

Flask - Templates

함수의 결과물로 HTML의 form에 특정 URL을 반환할 수 있습니다. 예를 들어, 다음 스크립트에서 hello() 함수는 ‘Hello World’를 <h1> 태그를 붙여서 반환합니다.


from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
  return '<html><body><h1>Hello World'</h1></body></html>'

if __name__ == '__main__':
  app.run(debug = True)

하지만 HTML 컨텐츠를 Python 코드로 생성하는 것은 쉽지 않습니다. 특히 변수 데이터와 조건문, 반복문과 같은 Python 언어 요소를 넣을 필요가 있다면 더욱 그러합니다. 그리고  HTML에서는 빈번한 escaping이 필요하게 될 것입니다.


이런 불편함을 극복할 수 있도록 Flask는 Jinja2 템플릿 엔진을 기본으로 사용합니다. 함수에서 하드코드 HTML을 반환하는 대신에, render_template() 함수를 사용해서 HTML 파일을 랜더링할 수 있습니다.


from flask import Flask
app = Flask(__name__)

@app.route('/')
def index():
  return render_template('hello.html')

if __name__ == '__main__':
  app.run(debug = True)


위 코드를 실행시키면 Flask는 templates 폴더에서 ‘hello.html’ 파일을 찾을 것입니다. templates 폴더는 지금 우리가 작성하는 스크립트와 동일한 위치에 있습니다. 다음은 Flask에서 사용하는 폴더 구조를 나타내고 있습니다.


Application folder
  • Hello.py
  • templates
    • hello.html


웹 템플릿 시스템(web template system)은 동적으로 변수 데이터를 삽입할 수 있는 HTML 스크립트의 디자인을 참조합니다. 웹 템플릿 시스템은 템플릿 엔진, 데이터 원본, 템플릿 프로세서로 구성됩니다. 위키피디아에서 web template system을 검색하면 자세한 설명을 확인할 수 있습니다.

330px-TempEngWeb016.svg.png


위 그림은 web template system에 대해서 간략하게 표현하고 있습니다. 데이터베이스에 있는 데이터 원본이 바로 우리가 보여주고 싶은 자료입니다. 이 데이터 원본을 좀더 효과적으로 전달하기 위해서 우리는 미리 만들어 둔 HTML 스크립트를 사용할 것입니다. 미리 준비해둔 HTML 스크립트에 지정되어 있는 변수에 데이터베이스에서 가져온 데이터를 집어넣어서 보여주면 사용자가 보기 좋은 형태로 구성된 웹 페이지를 볼 수 있게 됩니다. 미리 준비해둔 HTML 스크립트가 바로 웹 템플릿입니다. 데이터 원본을 웹 템플릿과 동적으로 연결하는 작업은 템플릿 엔진이 담당합니다.


Flask는 jinja2 템플릿 엔진을 사용합니다. 웹 템플릿은 변수와 표현식(이 경우에는 Python 표현식)의 placeholder가 배치된 HTML 문법을 포함하고 있습니다. 템플릿은 랜더링될 때, 데이터 원본에서 가져온 값으로 교체됩니다.


다음 코드를 hello.html이라는 이름으로 templates 폴더에 저장합니다.


<!doctype html>
<html>
  <body>
  
     <h1>Hello {{ name }}!</h1>
     
  </body>
</html>


그 다음 스크립트를 실행합니다.


from flask import Flask, render_template
app = Flask(__name__)

@app.route('/hello/<user>')
def hello_name(user):
  return render_template('hello.html', name = user)

if __name__ == '__main__':
  app.run(debug = True)


개발 서버가 동작하기 시작하고 나서, 브라우저를 열고 http://localhost:5000/hello/myName URL을 입력합니다.


URL이 입력되면 파이썬 코드는 URL을 라우팅합니다. myName은 user 인자의 매개변수로 전달됩니다. 그리고 render_template() 함수가 hello.html 스크립트를 랜더링할 때, name 인자의 매개변수로 myName을 전달합니다. hello.html 스크립트의 {{ name }} placeholder는 myName으로 대체되어 웹 브라우저에 랜더링됩니다. ‘Hello myName!’을 확인할 수 있을 것입니다.

jinja2 템플릿 엔진은 HTML에서 escaping하기 위해서 다음과 같은 구분 문자(여기에서는 hello.html 스크립트의 {}처럼 보통의 html 스크립트가 아니라 jinja2에서 관리하기 위해 사용하는 문자)를 사용합니다.


  • {% … %} 선언하기 위해서 사용
  • {{ … }} template output을 출력하기 위한 표현
  • {# … #} template output에 포함되지 않는 주석
  • # … # 줄 단위로 선언하기 위해서 사용


다음 코드는 template에서 조건문 선언을 보여줍니다. hello_score() 함수의 URL rule은 정수 매개변수를 받습니다. 전달받은 정수 인자는 hello.html template로 다시 전달됩니다. ‘marks’라는 변수로 전달받은 숫자값은 조건문에서 지정한대로 비교됩니다. 50보다 큰지 작은지 확인한 후, HTML 스크립트가 조건적으로 표시됩니다.


Python 코드는 다음과 같습니다.


from flask import Flask, render_template
app = Flask(__name__)

@app.route('/hello/<int:score>')
def hello_score(score):
  return render_template('hello.html', marks = score)

if __name__ == '__main__':
  app.run(debug = True)


hello.html template 스크립트는 다음과 같습니다.


<!doctype html>
<html>
  <body>
  
     {% if marks > 50 %}
     <h1> Your result is pass!</h1>
     {% else %}
     <h1>Your result is fail</h1>
     {% endif %}
     
  </body>
</html>


조건문 선언인 if-else, endif{% … %}로 감싸져있는 것을 확인하길 바랍니다.

이제 Python 스크립트를 실행하고 URL http://localhost:5000/hello/70을 방문합니다. 그리고 http://localhost:5000/hello/30도 한번 방문해보도록 합니다. 웹 브라우저에서 html 스크립트가 조건에 따라서 다르게 결과를 보여주는 것을 확인할 수 있습니다.


조건문뿐만 아니라 Python 반복문도 template 안에 넣을 수 있습니다. 다음 스크립트는 URL http://localhost:5000/result가 브라우저에서 열리면, result() 함수는 Python dictionary 객체를 result.html template로 전달합니다.


result.html은 Python dictionary 객체의 key와 value를 HTML 테이블의 셀로 화면에 표시하기 위해서 반복문을 사용하고 있습니다.


Python 코드는 다음과 같습니다.


from flask import Flask, render_template
app = Flask(__name__)

@app.route('/result')
def result():
 dict = {'phy':50,'che':60,'maths':70}
 return render_template('result.html', result = dict)

if __name__ == '__main__':
 app.run(debug = True)


templates 폴더에 들어갈 result.html 스크립트는 다음과 같습니다.


<!doctype html>
<html>
 <body>

    <table border = 1>
       {% for key, value in result.iteritems() %}
      
          <tr>
             <th> {{ key }} </th>
             <td> {{ value }} </td>
          </tr>
         
       {% endfor %}
    </table>
   
 </body>
</html>


늘 했던대로 Flask 웹 애플리케이션을 실행하고, 웹 브라우저에 URL http://localhost:5000/result를 입력합니다. 결과는 다음과 같을 것입니다.




웹 애플리케이션은 URL ‘/result’을 라우팅하여, 연결된 result() 함수를 실행합니다. result() 함수는 Python dictionary 객체를 생성하고, result.html 스크립트로 이 객체를 result 변수로 전달합니다. result.html 스크립트는 전달된 Python Dictionary 객체인 result의 key, value 값을 웹 브라우저에 표시합니다.

다음의 다룰 내용을 무엇인가요?

웹 애플리케이션에서 사용하는 javascript나 CSS 파일을 사용해볼 것입니다. 이와 관련하여 static 폴더에 대해서도 알아볼 것입니다.