Flask 应用程序中 templates를 사용하는 方法

저자는 Write for DOnations 프로그램의 일환으로 기부금을 받을 기관으로 Free and Open Source Fund를 선택했습니다.

서론

Flask는 Python 언어로 웹 애플리케이션을 만들기 위한 유용한 도구와 기능을 제공하는 경량급 Python 웹 프레임워크입니다.

웹 애플리케이션을 개발할 때 비즈니스 로직프레젠테이션 로직을 분리하는 것이 중요합니다. 비즈니스 로직은 사용자 요청을 처리하고 데이터베이스와 통신하여 적절한 응답을 구축하는 역할을 합니다. 프레젠테이션 로직은 데이터가 사용자에게 어떻게 표시되는지를 다루며, 일반적으로 HTML 파일을 사용하여 응답 웹 페이지의 기본 구조를 구축하고 CSS 스타일을 사용하여 HTML 구성 요소를 스타일링합니다. 예를 들어, 소셜 미디어 애플리케이션에서 사용자가 로그인하지 않은 경우에만 사용자 이름 필드와 비밀번호 필드를 표시할 수 있습니다. 사용자가 로그인한 경우 로그아웃 버튼을 대신 표시합니다. 이것이 프레젠테이션 로직입니다. 사용자가 사용자 이름과 비밀번호를 입력하면 Flask를 사용하여 비즈니스 로직을 수행할 수 있습니다: 요청에서 데이터(사용자 이름과 비밀번호)를 추출하고, 자격 증명이 올바른 경우 사용자를 로그인시키거나 오류 메시지로 응답합니다. 오류 메시지의 표시 방법은 프레젠테이션 로직에 의해 처리됩니다.

플라스크에서는 Jinja 템플릿 언어를 사용하여 HTML 템플릿을 렌더링할 수 있습니다. 템플릿은 고정된 내용과 동적 내용을 모두 포함할 수 있는 파일입니다. 사용자가 애플리케이션에서 무언가를 요청할 때(예: 인덱스 페이지나 로그인 페이지) Jinja를 사용하면 변수, if 문, for 루프, 필터 및 템플릿 상속과 같이 표준 HTML에서는 사용할 수 없는 많은 기능을 사용할 수 있는 HTML 템플릿으로 응답할 수 있습니다. 이러한 기능을 통해 유지 관리가 쉬운 HTML 페이지를 효율적으로 작성할 수 있습니다. 또한 Jinja는 자동으로 HTML을 이스케이프 처리하여 사이트 간 스크립팅(XSS) 공격을 방지합니다.

이 튜토리얼에서는 여러 HTML 파일을 렌더링하는 작은 웹 애플리케이션을 구축할 것입니다. 변수를 사용하여 서버에서 템플릿으로 데이터를 전달할 것입니다. 템플릿 상속은 반복을 피하는 데 도움이 될 것입니다. 조건문과 루프와 같은 템플릿에서 논리를 사용하고, 텍스트를 수정하기 위해 필터를 사용하며, 부트스트랩 툴킷을 사용하여 애플리케이션의 스타일을 지정할 것입니다.

전제 조건

1단계 — 템플릿 렌더링 및 변수 사용

환경을 활성화하고 Flask가 설치되어 있는지 확인한 후 애플리케이션 구축을 시작할 수 있습니다. 첫 번째 단계는 인덱스 페이지에 방문자를 환영하는 메시지를 표시하는 것입니다. Flask의 render_template() 헬퍼 함수를 사용하여 HTML 템플릿을 응답으로 제공할 것입니다. 또한 애플리케이션 측에서 템플릿으로 변수를 전달하는 방법도 살펴볼 것입니다.

먼저 flask_app 디렉토리에서 app.py라는 파일을 편집하기 위해 엽니다. nano 또는 즐겨 사용하는 텍스트 편집기를 사용하세요:

  1. nano app.py

app.py 파일 안에 다음 코드를 추가하세요:

flask_app/app.py

from flask import Flask, render_template

app = Flask(__name__)


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

파일을 저장하고 닫습니다.

이 코드 블록에서는 Flask 클래스와 render_template() 함수를 flask 패키지에서 가져옵니다. Flask 클래스를 사용하여 app이라는 Flask 애플리케이션 인스턴스를 생성합니다. 그런 다음 app.route() 데코레이터를 사용하여 일반 함수를 뷰 함수로 변환하는 뷰 함수 (HTTP 응답을 반환하는 Python 함수)를 hello()라는 이름으로 정의합니다. 이 뷰 함수는 render_template() 함수를 사용하여 index.html이라는 템플릿 파일을 렌더링합니다.

다음으로, flask_app 디렉토리 내의 templates라는 디렉토리에 index.html 템플릿 파일을 생성해야 합니다. Flask는 templates 디렉토리에서 템플릿을 찾으며, 이 디렉토리는 templates라고 불리기 때문에 이름이 중요합니다. flask_app 디렉토리 내부에 있는지 확인하고 다음 명령을 실행하여 templates 디렉토리를 생성하세요:

  1. mkdir templates

그런 다음, templates 디렉토리 내에 index.html이라는 파일을 열어 편집합니다. 여기서 index.html이라는 이름은 표준 필수 이름이 아닙니다; home.html이나 homepage.html 또는 원하는 다른 이름으로 부를 수 있습니다:

  1. nano templates/index.html

index.html 파일 내부에 다음 HTML 코드를 추가하세요:

flask_app/templates/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
</head>
<body>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
</body>
</html>

여기서 제목을 설정하고, H1 제목으로 Hello World! 메시지를 추가했으며, H2 제목으로 Welcome to FlaskApp! 메시지를 생성했습니다.

파일을 저장하고 닫습니다.

가상 환경이 활성화된 상태에서 flask_app 디렉토리 내부에 있는 동안, FLASK_APP 환경 변수를 사용하여 Flask에 애플리케이션(app.py 파일)에 대해 알리고, FLASK_ENV 환경 변수를 development로 설정하여 개발 모드로 애플리케이션을 실행하고 디버거에 접근할 수 있도록 합니다. 이를 위해 다음 명령어를 사용하세요(Windows에서는 export 대신 set을 사용):

  1. export FLASK_APP=app
  2. export FLASK_ENV=development

그런 다음, flask run 명령어를 사용하여 애플리케이션을 실행하세요:

  1. flask run

개발 서버가 실행 중인 상태에서 브라우저를 사용하여 다음 URL을 방문하세요:

http://127.0.0.1:5000/

페이지의 제목이 FlaskApp로 설정되어 있고, 두 개의 제목이 HTML로 렌더링되어 있는 것을 볼 수 있습니다.

웹 애플리케이션에서는 종종 애플리케이션의 Python 파일에서 HTML 템플릿으로 데이터를 전달해야 합니다. 이 애플리케이션에서 이를 수행하는 방법을 보여주기 위해, 현재 UTC 날짜와 시간을 포함하는 변수를 index 템플릿에 전달하고, 템플릿에서 해당 변수의 값을 표시할 것입니다.

서버를 계속 실행하고, 새 터미널에서 app.py 파일을 편집하기 위해 엽니다:

  1. nano app.py

Python 표준 라이브러리에서 datetime 모듈을 가져오고 index() 함수를 다음과 같이 수정하십시오:

flask_app/app.py
import datetime
from flask import Flask, render_template

app = Flask(__name__)


@app.route('/')
def hello():
    return render_template('index.html', utc_dt=datetime.datetime.utcnow())

파일을 저장하고 닫습니다.

여기서 datetime 모듈을 가져와 index.html 템플릿에 utc_dt라는 변수를 전달했습니다. 이 변수의 값은 현재 UTC 날짜와 시간인 datetime.datetime.utcnow()입니다.

다음으로, 변수의 값을 인덱스 페이지에 표시하려면 index.html 파일을 편집용으로 엽니다:

  1. nano templates/index.html

파일을 다음과 같이 수정하십시오:

flask_app/templates/index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>FlaskApp</title>
</head>
<body>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
    <h3>{{ utc_dt }}</h3>
</body>
</html>

파일을 저장하고 닫습니다.

utc_dt 변수의 값을 출력하기 위해 특수한 {{ ... }} 구분자를 사용하여 H3 제목을 추가했습니다.

브라우저를 열고 인덱스 페이지를 방문하십시오:

http://127.0.0.1:5000/

다음 이미지와 유사한 페이지가 표시됩니다:

이제 Flask 애플리케이션에서 HTML 템플릿을 사용하여 인덱스 페이지를 만들고, 템플릿을 렌더링하고, 변수 값을 전달하고 표시했습니다. 다음으로 템플릿 상속을 사용하여 코드 반복을 피할 것입니다.

2단계 — 템플릿 상속 사용

이 단계에서는 다른 템플릿과 공유할 수 있는 내용이 포함된 기본 템플릿을 만들 것입니다. 인덱스 템플릿을 편집하여 기본 템플릿을 상속받습니다. 그런 다음, 애플리케이션에 대한 자세한 정보를 찾을 수 있는 애플리케이션의 소개 페이지 역할을 할 새 페이지를 만들 것입니다.

기본 템플릿에는 애플리케이션의 제목, 탐색 모음 및 바닥글과 같이 다른 모든 템플릿에서 일반적으로 공유되는 HTML 구성 요소가 포함되어 있습니다.

먼저 템플릿 디렉토리 내에서 base.html이라는 새 파일을 편집용으로 엽니다:

  1. nano templates/base.html

다음 코드를 base.html 파일 안에 작성하세요:

flask_app/templates/base.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="#">FlaskApp</a>
        <a href="#">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

파일을 저장하고 닫습니다.

이 파일의 대부분의 코드는 표준 HTML, 제목, 탐색 링크에 대한 일부 스타일링, 아직 생성되지 않은 소개 페이지에 대한 인덱스 페이지 및 링크가 있는 탐색 모음, 그리고 페이지 내용에 대한 <div>입니다. (링크는 아직 작동하지 않습니다. 다음 단계에서는 페이지 간 링크 방법을 보여줍니다).

그러나 다음과 같은 강조 표시된 부분들은 Jinja 템플릿 엔진에 특정한 것입니다:

  • {% block title %} {% endblock %}: 제목을 위한 자리표시자 역할을 하는 블록입니다. 나중에 이를 다른 템플릿에서 사용하여 애플리케이션의 각 페이지에 대한 사용자 정의 제목을 제공할 수 있으며, 매번 전체 <head> 섹션을 다시 작성하지 않아도 됩니다.

  • {% block content %} {% endblock %}: 하위 템플릿(base.html에서 상속받는 템플릿)에 따라 내용이 대체될 또 다른 블록입니다.

이제 기본 템플릿이 있으므로 상속을 활용할 수 있습니다. index.html 파일을 엽니다:

  1. nano templates/index.html

그런 다음 내용을 다음과 같이 대체하세요:

flask_app/templates/index.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Index {% endblock %}</h1>
    <h1>Hello World!</h1>
    <h2>Welcome to FlaskApp!</h2>
    <h3>{{ utc_dt }}</h3>
{% endblock %}

여기에서 {% extends %} 태그를 사용하여 base.html 템플릿을 상속합니다. 그런 다음 이전 코드 블록의 content 블록 내용으로 기본 템플릿의 content 블록을 대체하여 확장합니다.

이 콘텐츠 블록에는 제목 블록 내에 Index라는 텍스트가 있는 <h1> 태그가 포함되어 있으며, 이는 원래 base.html 템플릿의 title 블록을 Index라는 텍스트로 대체하여 전체 제목이 Index - FlaskApp가 됩니다. 이렇게 하면 페이지의 제목과 기본 템플릿에서 상속된 네비게이션 바 아래에 나타나는 제목으로 모두 작동하므로 동일한 텍스트를 두 번 반복하지 않아도 됩니다.

그런 다음 Hello World!라는 텍스트가 있는 <h1> 제목, <h2> 제목, utc_dt 변수의 값을 포함하는 <h3> 제목과 같은 몇 가지 제목이 더 있습니다.

템플릿 상속을 통해 필요할 때마다 반복하지 않고 다른 템플릿(base.html의 경우)에 있는 HTML 코드를 재사용할 수 있습니다.

파일을 저장하고 닫은 다음 브라우저에서 인덱스 페이지를 새로 고칩니다. 페이지는 다음과 같이 표시됩니다:

다음으로 About 페이지를 만듭니다. app.py 파일을 열어 새로운 경로를 추가하세요:

  1. nano app.py

파일 끝에 다음 경로를 추가하세요:

flask_app/app.py

# ...
@app.route('/about/')
def about():
    return render_template('about.html')

여기서 app.route() 데코레이터를 사용하여 about()이라는 뷰 함수를 만듭니다. 이 함수 내에서 about.html 템플릿 파일 이름을 인수로 사용하여 render_template() 함수를 호출한 결과를 반환합니다.

파일을 저장하고 닫습니다.

about.html이라는 템플릿 파일을 편집하기 위해 엽니다:

  1. nano templates/about.html

파일에 다음 코드를 추가합니다:

flask_app/templates/about.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} About {% endblock %}</h1>
    <h3>FlaskApp is a Flask web application written in Python.</h3>
{% endblock %}

여기서 extends 태그를 사용하여 기본 템플릿을 상속받고, 기본 템플릿의 content 블록을 페이지 제목으로도 사용되는 <h1> 태그로 대체하고, 애플리케이션에 대한 정보가 포함된 <h3> 태그를 추가합니다.

파일을 저장하고 닫습니다.

개발 서버가 실행 중인 상태에서 브라우저를 사용하여 다음 URL을 방문하세요:

http://127.0.0.1:5000/about

다음과 유사한 페이지가 나타납니다:

내비게이션 바와 제목의 일부가 기본 템플릿에서 상속되는 방식을 확인하세요.

이제 기본 템플릿을 만들고 인덱스 페이지와 정보 페이지에서 사용하여 코드 반복을 피했습니다. 현재 내비게이션 바의 링크는 아무 것도 하지 않습니다. 다음 단계에서는 내비게이션 바 링크를 수정하여 템플릿 간 라우트를 연결하는 방법을 배우게 됩니다.

3단계 — 페이지 간 링크 연결

이 단계에서는 url_for() 헬퍼 함수를 사용하여 템플릿에서 페이지 간을 연결하는 방법을 배우게 됩니다. 기본 템플릿의 네비게이션 바에 인덱스 페이지와 About 페이지에 대한 두 개의 링크를 추가할 것입니다.

먼저 편집을 위해 기본 템플릿을 엽니다:

  1. nano templates/base.html

파일을 다음과 같이 편집하세요:

flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('hello') }}">FlaskApp</a>
        <a href="{{ url_for('about') }}">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

여기서 특별한 url_for() 함수를 사용하여 주어진 뷰 함수에 대한 URL을 반환합니다. 첫 번째 링크는 hello() 뷰 함수의 경로(인덱스 페이지)에 연결됩니다. 두 번째 링크는 about() 뷰 함수의 경로에 연결됩니다. 경로(/ 또는 /about)가 아닌 뷰 함수의 이름을 전달한다는 점에 주의하세요.

url_for() 함수를 사용하여 URL을 구축하면 URL을 더 잘 관리할 수 있습니다. 하드코딩된 URL을 사용하면 경로를 편집할 때 링크가 깨질 수 있습니다. url_for()를 사용하면 경로를 편집하고 링크가 예상대로 작동하는지 보장할 수 있습니다. url_for() 함수는 특수 문자 이스케이프와 같은 다른 작업도 처리합니다.

파일을 저장하고 닫습니다.

이제 인덱스 페이지로 이동하여 네비게이션 바의 링크를 테스트해보세요. 예상대로 작동하는 것을 볼 수 있습니다.

당신은 템플릿에서 다른 경로로 연결하기 위해 url_for() 함수를 사용하는 방법을 배웠습니다. 다음으로, 설정한 조건에 따라 템플릿에 표시되는 내용을 제어하기 위해 몇 가지 조건문을 추가하고, 템플릿에서 for 루프를 사용하여 목록 항목을 표시할 것입니다.

4단계 — 조건문과 반복문 사용

이 단계에서는 템플릿에 if 문을 사용하여 특정 조건에 따라 표시할 내용을 제어할 것입니다. 또한 for 루프를 사용하여 Python 목록을 통과하고 목록의 각 항목을 표시할 것입니다. 댓글을 목록으로 표시하는 새 페이지를 추가할 것입니다. 짝수 인덱스 번호를 가진 댓글은 파란색 배경을 가지며, 홀수 인덱스 번호를 가진 댓글은 회색 배경으로 표시됩니다.

먼저, 댓글 페이지를 위한 경로를 생성하겠습니다. app.py 파일을 편집하기 위해 엽니다:

  1. nano app.py

파일 끝에 다음 경로를 추가하십시오:

flask_app/app.py

# ...

@app.route('/comments/')
def comments():
    comments = ['This is the first comment.',
                'This is the second comment.',
                'This is the third comment.',
                'This is the fourth comment.'
                ]

    return render_template('comments.html', comments=comments)

위의 경로에서, 네 개의 항목을 포함하는 comments라는 Python 목록이 있습니다. (이 댓글은 일반적으로 이와 같이 하드코딩되는 대신 실제 시나리오에서 데이터베이스에서 올 것입니다.) 마지막 줄에서 comments.html이라는 템플릿 파일을 반환하며, 목록을 포함하는 comments라는 변수를 템플릿 파일에 전달합니다.

파일을 저장하고 닫습니다.

다음으로, templates 디렉토리 내에 새로운 comments.html 파일을 열어 편집합니다:

  1. nano templates/comments.html

파일에 다음 코드를 추가하세요:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
        <div style="padding: 10px; background-color: #EEE; margin: 20px">
            <p style="font-size: 24px">{{ comment }}</p>
        </div>
        {% endfor %}
    </div>
{% endblock %}

여기서 base.html 템플릿을 확장하고 content 블록의 내용을 대체합니다. 먼저, 페이지의 제목 역할을 하는 <h1> 제목을 사용합니다.

{% for comment in comments %} 줄에서 Jinja for 루프를 사용하여 comments 목록의 각 댓글을 순회합니다(이 목록은 comment 변수에 저장됨). <p style="font-size: 24px">{{ comment }}</p> 태그에서 댓글을 표시합니다. 이는 일반적인 Jinja 변수 표시 방법과 동일합니다. for 루프의 끝을 {% endfor %} 키워드를 사용하여 표시합니다. 이는 Python for 루프와 다르게 Jinja 템플릿에서는 특별한 들여쓰기가 없습니다.

파일을 저장하고 닫습니다.

개발 서버가 실행 중인 상태에서 브라우저를 열고 댓글 페이지를 방문하세요:

http://127.0.0.1:5000/comments

다음과 유사한 페이지가 나타납니다:

이제 템플릿에서 if 조건문을 사용하여 홀수 인덱스 번호의 댓글은 회색 배경으로, 짝수 인덱스 번호의 댓글은 파란색 배경으로 표시하겠습니다.

comments.html 템플릿 파일을 열어 편집하세요:

  1. nano templates/comments.html

다음과 같이 편집합니다:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index % 2 == 0 %}
                {% set bg_color = '#e6f9ff' %}
            {% else %}
                {% set bg_color = '#eee' %}
            {% endif %}

            <div style="padding: 10px; background-color: {{ bg_color }}; margin: 20px">
                <p>#{{ loop.index }}</p>
                <p style="font-size: 24px">{{ comment }}</p>
            </div>
        {% endfor %}
    </div>
{% endblock %}

이 새로운 편집으로, {% if loop.index % 2 == 0 %} 줄에 if 문을 추가했습니다. loop 변수는 현재 루프에 대한 정보에 접근할 수 있게 해주는 특별한 Jinja 변수입니다. 여기서는 loop.index를 사용하여 현재 항목의 인덱스를 가져옵니다. 이 인덱스는 Python 리스트와 달리 1부터 시작합니다.

if 문은 % 연산자를 사용하여 인덱스가 짝수인지 확인합니다. 인덱스 숫자를 2로 나눈 나머지를 확인하며, 나머지가 0이면 인덱스 숫자가 짝수이고, 그렇지 않으면 인덱스 숫자가 홀수입니다. {% set %} 태그를 사용하여 bg_color라는 변수를 선언합니다. 인덱스 숫자가 짝수이면 푸른색으로 설정하고, 홀수이면 bg_color 변수를 회색으로 설정합니다. 그런 다음 bg_color 변수를 사용하여 댓글을 포함하는 <div> 태그의 배경색을 설정합니다. 댓글 텍스트 위에 loop.index를 사용하여 현재 인덱스 번호를 <p> 태그에 표시합니다.

파일을 저장하고 닫습니다.

브라우저를 열고 댓글 페이지를 방문하세요:

http://127.0.0.1:5000/comments

새로운 댓글 페이지를 볼 수 있습니다:

이는 if 문을 사용하는 방법에 대한 데모였습니다. 하지만 특별한 loop.cycle() Jinja 헬퍼를 사용하여 동일한 효과를 얻을 수도 있습니다. 이를 시연하기 위해 comments.html 파일을 엽니다.

  1. nano templates/comments.html
flask_app/templates/comments.html

{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            <div style="padding: 10px;
                        background-color: {{ loop.cycle('#EEE', '#e6f9ff') }};
                        margin: 20px">
                <p>#{{ loop.index }}</p>
                <p style="font-size: 24px">{{ comment }}</p>
            </div>
        {% endfor %}
    </div>
{% endblock %}

여기서 if/else 문을 제거하고 loop.cycle('#EEE', '#e6f9ff') 헬퍼를 사용하여 두 색상 사이를 순환합니다. background-color의 값은 한 번은 #EEE가 되고 다른 번은 #e6f9ff가 됩니다.

파일을 저장하고 닫습니다.

브라우저에서 댓글 페이지를 열고 새로 고침하면 if 문과 동일한 효과를 볼 수 있습니다.

if 문은 페이지에 표시되는 내용을 제어하는 등 여러 용도로 사용할 수 있습니다. 예를 들어, 두 번째 댓글을 제외한 모든 댓글을 표시하려면 loop.index != 2 조건으로 if 문을 사용하여 두 번째 댓글을 필터링할 수 있습니다.

댓글 템플릿을 엽니다:

  1. nano templates/comments.html

그리고 다음과 같이 편집합니다:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment }}</p>
                </div>
            {% endif %}
        {% endfor %}
    </div>
{% endblock %}

여기서 {% if loop.index != 2 %}를 사용하여 인덱스가 2가 아닌 댓글만 표시합니다. 즉, 두 번째 댓글을 제외한 모든 댓글을 표시합니다. 또한 loop.cycle() 헬퍼 대신 하드코딩된 값을 사용하여 배경색을 간단하게 설정하고 나머지는 변경하지 않습니다. if 문은 {% endif %}로 끝냅니다.

파일을 저장하고 닫습니다.

댓글 페이지를 새로 고침하면 두 번째 댓글이 표시되지 않습니다.

이제 사용자가 네비게이션 바에서 댓글 페이지로 이동할 수 있는 링크를 추가해야 합니다. 기본 템플릿을 편집하기 위해 엽니다:

  1. nano templates/base.html
flask_app/templates/base.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>{% block title %} {% endblock %} - FlaskApp</title>
    <style>
        nav a {
            color: #d64161;
            font-size: 3em;
            margin-left: 50px;
            text-decoration: none;
        }
    </style>
</head>
<body>
    <nav>
        <a href="{{ url_for('hello') }}">FlaskApp</a>
        <a href="{{ url_for('comments') }}">Comments</a>
        <a href="{{ url_for('about') }}">About</a>
    </nav>
    <hr>
    <div class="content">
        {% block content %} {% endblock %}
    </div>
</body>
</html>

여기서 url_for() 헬퍼를 사용하여 comments() 뷰 함수에 링크합니다.

파일을 저장하고 닫습니다.

이제 네비게이션 바에 댓글 페이지로 연결되는 새 링크가 있습니다.

템플릿에서 if 문을 사용하여 특정 조건에 따라 표시할 내용을 제어했습니다. Python 목록을 순회하고 목록의 각 항목을 표시하기 위해 for 루프를 사용했으며, Jinja의 특수 loop 변수에 대해 배웠습니다. 다음으로, Jinja 필터를 사용하여 변수 데이터가 표시되는 방식을 제어할 것입니다.

5단계 — 필터 사용

이 단계에서는 템플릿에서 Jinja 필터를 사용하는 방법을 배웁니다. 이전 단계에서 추가한 댓글을 대문자로 변환하기 위해 upper 필터를 사용하고, 문자열 시퀀스를 하나의 문자열로 결합하기 위해 join 필터를 사용하며, safe 필터를 사용하여 신뢰할 수 있는 HTML 코드를 이스케이프하지 않고 렌더링하는 방법을 배웁니다.

먼저, 댓글 페이지의 댓글을 대문자로 변환하겠습니다. comments.html 템플릿을 편집용으로 엽니다:

  1. nano templates/comments.html

다음과 같이 편집합니다:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
    </div>
{% endblock %}

여기에서 파이프 기호(|)를 사용하여 필터upper를 추가했습니다. 이렇게 하면 comment 변수의 값을 대문자로 변경합니다.

파일을 저장하고 닫습니다.

개발 서버가 실행 중인 상태에서 브라우저로 댓글 페이지를 엽니다:

http://127.0.0.1:5000/comments

필터를 적용한 후 모든 댓글이 대문자로 표시되는 것을 볼 수 있습니다.

필터는 괄호 안에 인수를 사용할 수도 있습니다. 이를 보여주기 위해 join 필터를 사용하여 comments 목록의 모든 댓글을 결합할 것입니다.

댓글 템플릿을 엽니다:

  1. nano templates/comments.html

다음과 같이 편집합니다:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            <p>{{ comments | join(" | ") }}</p>
        </div>
    </div>
{% endblock %}

여기에 <hr> 태그와 <div> 태그를 추가하여 join() 필터를 사용하여 comments 목록의 모든 댓글을 결합했습니다.

파일을 저장하고 닫습니다.

댓글 페이지를 새로 고치면 다음과 유사한 페이지가 표시됩니다:

보시다시피, comments 목록은 파이프 기호로 구분되어 표시되며, 이는 join() 필터에 전달한 내용입니다.

또 다른 중요한 필터는 safe 필터로, 브라우저에서 신뢰할 수 있는 HTML을 렌더링할 수 있게 해줍니다. 이를 설명하기 위해 {{ }} Jinja 구분자를 사용하여 댓글 템플릿에 HTML 태그를 포함한 텍스트를 추가하겠습니다. 실제 상황에서는 이것이 서버로부터 변수로 전달될 것입니다. 그런 다음 join() 인수를 파이프 기호 대신 <hr> 태그로 수정하겠습니다.

댓글 템플릿을 엽니다:

  1. nano templates/comments.html

다음과 같이 수정합니다:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            {{ "<h1>COMMENTS</h1>" }}
            <p>{{ comments | join(" <hr> ") }}</p>
        </div>
    </div>
{% endblock %}

여기서 "<h1>COMMENTS</h1>" 값을 추가하고 join 인수를 <hr> 태그로 변경했습니다.

파일을 저장하고 닫습니다.

댓글 페이지를 새로 고치면 다음과 유사한 페이지가 나타납니다:

보시다시피, HTML 태그가 렌더링되지 않았습니다. 이는 Jinja의 안전 기능으로, 일부 HTML 태그는 유해할 수 있으며 Cross Site Scripting (XSS) 공격을 일으킬 수 있습니다. 브라우저에서 렌더링되는 HTML은 신뢰할 수 있는 것으로 제한해야 합니다.

위의 HTML 태그를 렌더링하려면 댓글 템플릿 파일을 엽니다:

  1. nano templates/comments.html

safe 필터를 추가하여 수정합니다:

flask_app/templates/comments.html
{% extends 'base.html' %}

{% block content %}
    <h1>{% block title %} Comments {% endblock %}</h1>
    <div style="width: 50%; margin: auto">
        {% for comment in comments %}
            {% if loop.index != 2 %}
                <div style="padding: 10px;
                            background-color: #EEE;
                            margin: 20px">
                    <p>#{{ loop.index }}</p>
                    <p style="font-size: 24px">{{ comment | upper }}</p>
                </div>
            {% endif %}
        {% endfor %}
        <hr>
        <div>
            {{ "<h1>COMMENTS</h1>" | safe }}
            <p>{{ comments | join(" <hr> ") | safe }}</p>
        </div>
    </div>
{% endblock %}

<p>{{ comments | join(" <hr> ") | safe }}</p> 라인과 같이 필터를 연결할 수도 있습니다. 각 필터는 이전 필터링의 결과에 적용됩니다.

파일을 저장하고 닫습니다.

댓글 페이지를 새로 고치면 HTML 태그가 예상대로 렌더링되는 것을 볼 수 있습니다:

경고: 알 수 없는 데이터 소스의 HTML에 safe 필터를 사용하면 애플리케이션이 XSS 공격에 노출될 수 있습니다. 렌더링하는 HTML이 신뢰할 수 있는 소스에서 온 것이 아니라면 사용하지 마십시오.

자세한 내용은 내장된 Jinja 필터 목록을 확인하십시오.

이제 Jinja 템플릿에서 필터를 사용하여 변수 값을 수정하는 방법을 배웠습니다. 다음으로 Bootstrap 툴킷을 통합하여 애플리케이션의 스타일을 지정할 것입니다.

6단계 — Bootstrap 통합

이번 단계에서는 Bootstrap 툴킷을 사용하여 애플리케이션의 스타일을 지정하는 방법을 배울 것입니다. 기본 템플릿에 Bootstrap 네비게이션 바를 추가하여 기본 템플릿에서 상속받는 모든 페이지에 나타나게 할 것입니다.

Bootstrap 툴킷은 애플리케이션의 시각적 매력을 높이는 데 도움이 됩니다. 또한 이 툴킷은 반응형 웹 페이지를 웹 애플리케이션에 통합하여 모바일 브라우저에서도 잘 작동하게 해줍니다. 이를 위해 자신의 HTML, CSS, JavaScript 코드를 작성하지 않아도 됩니다.

Bootstrap을 사용하려면 기본 템플릿에 추가하여 다른 모든 템플릿에서 사용할 수 있도록 해야 합니다.

base.html 템플릿을 editing 하기 위해 개 aperture 열기:

  1. nano templates/base.html

다음과 같이 보이도록 editing 하시오:

flask_app/templates/base.html
<!doctype html>
<html lang="en">
  <head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- Bootstrap CSS -->
    <link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-KyZXEAg3QhqLMpG8r+8fhAXLRk2vvoC2f3B09zVXn8CA5QIVfZOJ3BCsw2P0p/We" crossorigin="anonymous">

    <title>{% block title %} {% endblock %} - FlaskApp</title>
  </head>
  <body>
    <nav class="navbar navbar-expand-lg navbar-light bg-light">
    <div class="container-fluid">
        <a class="navbar-brand" href="{{ url_for('hello') }}">FlaskApp</a>
        <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation">
        <span class="navbar-toggler-icon"></span>
        </button>
        <div class="collapse navbar-collapse" id="navbarNav">
        <ul class="navbar-nav">
            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('comments') }}">Comments</a>
            </li>
            <li class="nav-item">
              <a class="nav-link" href="{{ url_for('about') }}">About</a>
            </li>
        </ul>
        </div>
    </div>
    </nav>
    <div class="container">
        {% block content %} {% endblock %}
    </div>

    <!-- Optional JavaScript -->

    <script src="https://cdn.jsdelivr.net/npm/[email protected]/dist/js/bootstrap.bundle.min.js" integrity="sha384-U1DAWAznBHeqEIlVSCgzq+c9gqGAJn5c/t99JyeKa9xxaYpSvHU5awsuZVVFIhvj" crossorigin="anonymous"></script>

  </body>
</html>

위의 코드 대부분은 Bootstrap을 사용하기 위해 필요한 boilerplate 입니다. 여러 meta tags가 있고, <head> 섹션에 Bootstrap CSS 파일의 링크가 있고, 아래에 옵션적인 JavaScript의 링크가 있습니다. 코드의 표시 영역은 이전 단계에서 설명한 Jinja 코드입니다. Bootstrap에게 각 요소를 어떻게 표시하는지 特定的 tags와 CSS classes를 사용하는 것을 주의 깊게 봐주세요.

위의 <nav> tag 안에, <a> tag가 있는 navbar-brand class가 있습니다. 이것은 ナビ バー 안의 브랜드 링크를 결정합니다. <ul class="navbar-nav"> tag 안에, <a> tag 안에 있는 <li> tag에 있는 일반적인 ナビ バー 아이템이 있습니다.

이러한 tags와 CSS classes에 대해 자세히 배우려면 Bootstrap components을 보세요.

파일을 저장하고 닫으십시오.

開発 서버가 실행 중이면, 인덱스 页面을 브라우저로 개 aperture 열기:

http://127.0.0.1:5000/

다음과 같은 页面을 보게 됩니다:

이제 Bootstrap components를 사용하여 Flask 응용 프로그램의 모든 템플릿에서 요소를 스타일링할 수 있습니다.

결론

이제 Flask 웹 애플리케이션에서 HTML 템플릿을 사용하는 방법을 알게 되었습니다. 서버에서 템플릿으로 데이터를 전달하기 위해 변수를 사용하고, 반복을 피하기 위해 템플릿 상속을 사용했으며, if 조건문과 for 루프와 같은 요소를 포함시켰고, 다른 페이지 간의 링크를 설정했습니다. 텍스트를 수정하고 신뢰할 수 있는 HTML을 표시하기 위해 필터에 대해 배웠으며, 애플리케이션에 Bootstrap을 통합했습니다.

Flask에 대해 더 읽어보고 싶다면 Flask 주제 페이지를 확인해보세요.

Source:
https://www.digitalocean.com/community/tutorials/how-to-use-templates-in-a-flask-application