본문 바로가기
WebFramework/Python Flask

[Python Flask] 3. Jinja Statement를 활용한 HTML 제어문 및 반복문

by Rosmary 2024. 2. 29.
728x90
반응형

 

 

 

 

지난 포스팅에서는 Flask에서 사용하는 Jinja Expression - 제어자, 필자는 지난 포스팅에서 템플릿 변수라고 소개했다 - 를 사용하여 HTML 파일에 Python의 변수를 입력하는 방법에 대해 알아보았다. 그런데, 지난 포스팅의 마지막 부분에서 확인했듯이, 로그인을 진행하지 않았음에도 화면 아랫부분에에 출력되는 "로그인 결과"가 영 거슬린다.

 

 

필자가 만든 페이지로 첫 접속을 시도했을 때는 GET으로만 페이지를 불러오기 때문에 username의 입력값이 없어 로그인 결과가 None으로 출력되는데, 이게 은근히 보기가 싫다. 하지만 지난 포스팅에서도 언급했듯이 HTML은 - 프로그래밍 언어가 아니고 - 문서이기 때문에 저 로그인 결과와 관련된 태그를 직접 삭제하는 것이 불가능하고, 별도의 방식을 사용해야한다.

 

이번 포스팅에서는 Jinja의 statement라는 것을 통해 HTML에서 조건 분기 및 반복문을 진행해보려한다. 

 

 

1. Jinja Statement의 필요성

 

위의 예시처럼 username이 None 값으로 들어간 상황이라고 가정해보자. 즉, "GET"으로 페이지에 접근하는 경우다.  render_template으로 HTML 파일을 반환하지 않는다면, 아마 아래와 같은 코드가 "/"로 routing하는 함수 아래에 들어가게 될 것이다.

 

이렇게 쓰라고 만든 Flask가 아닐텐데 ...?

 

뭐... 동작은 잘 하는 코드지만, Python에 HTML을 전부 때려박아놓아서 프로그램 코드인지 팔만대장경인지 구분이 안 될 정도다. 이런 식으로 코드를 작성하면 추후 HTML 파일을 수정해야 할 때 Python 코드를 한참 뒤져봐야한다는 문제가 발생한다. 당연히 Flask에서 제공하는 render_template도 사실상 무용지물이 되어버리고 말이다(설렁탕을 사왔는데, 왜 먹지를 못하니...)

 

그런데 앞서 언급했듯이 HTML은 프로그래밍 언어가 아니기 때문에 python으로부터 값을 받기만 할 뿐 자체적으로 전달받은 값으로 연산을 진행하지 못한다. 따라서 Jinja의 문법을 사용하여 HTML이 전달받은 값으로 조건 분기를 진행하도록 만들어주어야 한다.

 

 

2. Jinja Statement

 

지금까지는 Jinja 문법 중 Python 변수값을 호출하는 Expression {{ }} 만 적용해보았는데, 사실 Expression 외에도 statement(선언문)라고 불리는, 간략한 반복과 조건 분기를 진행할 수 있도록 만든 문법이 존재한다. 모양은 아래와 같이 생겼다.

1
2
<!-- Python / Jinja Statement -->
{%  조건문 및 반복문 %}
cs

 

HTML에서 변수를 받는 Expressions가 {{ }}로 중괄호 2개를 겹쳐쓰는 것과는 달리, Statement는 중괄호 하나 안에 퍼센트 기호를 양 옆으로 배치한 모양이다 - JSP Statement와도 상당히 유사한 모양이다. statement 내부에는 조건문을 사용할지, 반복문을 사용할지에 따라 다른 내용이 입력된다.

 

(1) IF 조건문

 

먼저 if 문부터 적용해보자. if 문은 조건 분기를 위한 문법이다. HTML 내에서 아래의 형태로 사용된다.

1
2
3
4
5
6
7
8
<!-- Jinja Statement: IF문 단독  -->
<div>
    {% if 조건 %}
      조건이 일치하는 경우 출력할 HTML 작성
    {% endif%}
</div>
cs

 

 

필자가 만든 웹 사이트는 첫 접속 시, POST로 전달되는 값이 없다. 따라서 접속 시 HTML로 돌려받는 Dictionary 데이터에서 Key가 username인 값은 무조건 None으로 반환된다. 그럼 HTML에서는 아래와 같이 Jinja If 문을 작성할 수 있을 것이다.

1
2
3
4
5
6
7
8
9
10
<div>
<p>데이터 전달: {{ data.protocol }}</p>

    {% if data.username != None %}
        <h3>로그인 결과</h3>
        <p>username '{{ data.username }}' 로그인 {{ data.result }} </p>
    {% endif %}
 
</div>
cs

 

 

Jinja Statemen 사용 시 주의해야 할 점이 두 가지 가 있는데,  첫 번 째는 Python에서 HTML로 전달되는 변수 인자는 Statement 문 내에서 Expression 형태로 사용되지 않는다는 점이다. 위의 코드에서도 볼 수 있듯이 Jinja Statement는 python의 변수를 직접 명시하도록 되어 있다. 

 

다음으로는 Statement가 HTML 문에서 선언되고나면, 어디서 마무리되는지 확실히 명시해주어야 한다는 점이다. 위의 코드를 보면 {% endif %}라는 코드가 있는데, IF 문의 조건을 어디까지 수행할 것인지 HTML 파일에 알려주는 것이라 생각하면 된다. 마치 Linux Bash의 if 문과 사용 방법이 유사하다고 보면 된다.

 

위의 코드를 적용하고 다시 Flask를 실행해보자. 필자는 GET, POST 통신을 확인하기 위한 HTML 태그만 제외하고, 결과를 출력하는 태그는 Jinja IF statement로 이동시켰다.

 

 

단순히 페이지 접속만 진행하는 경우에는 이전과 달리 로그인 결과가 지저분하게 출력되지 않음을 확인할 수 있다. 이제 로그인을 진행해보자.

 

 

 

(2) if - else, if - elif , if - elif - else

 

현재 작성한 코드는 페이지를 GET으로 호출하거나 POST로 호출하거나 모두 통신 프로토콜이 출력되도록 코드가 작성되어 있다. 그런데, 필자는 로그인 계정 정보가 입력되지 않는 경우, 즉 GET 인 경우에만 통신 프로토콜 정보를 출력하도록 수정하고 싶다. 그럼, data.username이 None 값인 경우에만 통신 프로토콜을 출력하게 만들어주면 된다. 이미 위의 코드에서 data.username이 None이 아닌 경우에 대한 조건을 넣었으니 이 아래에 else와 관련된 statement을 추가하면 될 것이다. 

 

IF 문 외에 Else를 추가하는 경우 Jinja Statement는 아래와 같은 형태를 보이게 된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
<div>
    <!-- Jinja Statement: IF-ELSE -->
    {% if 조건 %}
 
        조건이 일치하는 경우 사용할 HTML 태그 작성
 
    {% else %}
        
        조건이 일치하지 않는 경우 사용할 HTML 태그 작성
 
    {% endif %}
 
</div>
cs

 

만약 IF - ELIF를 사용하는 경우라면 아래와 같이 사용하면 된다. 

1
2
3
4
5
6
7
8
9
10
11
12
13
<div>
    <!-- Jinja Statement: IF-ELIF -->
    {% if 조건1 %}
 
        조건이 일치하는 경우 사용할 HTML 태그 작성
 
    {% elif 조건2 %}
        
        조건이 일치하지 않는 경우 사용할 HTML 태그 작성
 
    {% endif %}
 
</div>
cs

 

IF - ELIF - ELSE 문도 마찬가지 포맷으로 사용하면 된다.

 

이제 필자는 계정 정보가 일치하면 파란 글씨로 결과를 표시하고, 아닌 경우라면 빨간 글씨로 결과를 표시하려 한다.

중복되는 코드들이 있는데, if-elif-else를 구현하기 위해 어쩔 수 없다.

 

결과는 아래와 같이 나타난다.

 

 

 

(3) for 문

 

이번에는 조금 색다른 내용을 추가해보려한다. 필자가 만든 사이트는 alex라는 사람이 로그인하면 국어, 영어, 수학(그 놈의 국영수) 점수가 출력되도록 만들어보려한다. 이를 위해 HTML로 전달하는 Data에 아래와 같이 점수와 관련된 내용을 추가했다.

 

 

 

이 내용을 이제 HTML의 table 태그를 사용해서 출력해보자. 우선은 코드를 아래와 같이 작성했다. 

 

과목명 수정 안했다...

 

 

위의 코드를 실행하면 아래처럼 로그인이 정상적으로 진행된 경우 Alex의 국, 영, 수 성적이 표로 표시된다. 

 

과목명과 표 디자인은 잠시 무시하도록 하자...

 

그런데, HTML 파일을 보면 점수를 입력하는 부분이 <tr> 태그로 반복되는 것이 보인다. 그에 더해서 전달받는 데이터들도 dictionary 형태인지라 반복문을 돌리면 훨씬 더 수월하게 데이터를 HTML 파일에 적용할 수 있을 듯 하다.

 

Jinja Statement는 너무도 당연히 For 문도 지원을 한다. For 문의 Jinja Statement 형태는 아래와 같다.

1
2
3
4
5
6
7
8
<div>
    <!-- Jinja Statement: For -->
    {% for ITEM_NAME in ITERABLE_DATA %}
 
        반복문으로 진행할 HTML 태그  
 
    {% endfor %}
</div>
cs

 

 

앞서 보았던 Jinja statement와 큰 차이는 없다. 다만 현재 필자의 경우 점수 정보를 Dictionary 형태로 돌려받기 때문에 과목명과 점수를 별도로 분리하여 사용해야할 필요성이 있다. 따라서 아래와 같이 Jinja for 문을 두 번 작성하여 HTML 코드에 적용하였다.

 

 

 

다행히 Jinja statement는 반환받는 변수들의 타입에 따른 매서드 사용이 가능한 듯 하다. 위의 경우도 아랫쪽 for 문은  Dictionary.values()로 점수 정보 데이터만 List 형태로 출력이 가능한 것이 확인된다.

 

app.py 재실행 후, 정상 로그인을 진행하여 출력되는 내용은 아래와 같이 나타난다.

 

 

 

참고로 Jinja의 for 문은 Jinja 모듈 내에 내장된 함수를 통해 range()를 사용하여 for 문을 돌릴 수 있는 기능을 제공하고 있다. for 문의 range를 가장 많이 사용하는 구구단을 화면에 출력하려면 아래와 같이 사용하면 된다.

 

 

 

마찬가지로 테이블이 예쁘지는 않지만, 로그인에 성공하면 결과는 잘 나타나는 것을 확인할 수 있다.

 

 

 


 

 

Jinja statement에서는 python의 몇몇 기능들을 사용할 수 있는데, 사용할 수 있는 기능은 jinja의 공식 documentation을 참고하면 된다. 공식 documentation을 보니 일본 신사 모양의 아이콘이 있는데, 신사(神社, じんじゃ)의 일본어 발음을 따 온듯 하다(jinjya라고 써야되는거 아닌가 싶긴 한데 넘어가자)

 

Jinja 공식 Documentation 사이트

 

Template Designer Documentation — Jinja Documentation (3.1.x)

Template Designer Documentation This document describes the syntax and semantics of the template engine and will be most useful as reference to those creating Jinja templates. As the template engine is very flexible, the configuration from the application

jinja.palletsprojects.com

 

 

의외로 jinja에서 while 문은 제공하지 않는다. 아마도 HTML에서 while문을 얼마 쓰지 않을 듯 해서 안 만든 듯 하다.

 

 

 

End.

 

 

 

반응형

댓글