** 2.x.x의 공식문서와 3.x.x의 공식문서 및 위키독스를 참고하였음
공식문서 : https://jinja.palletsprojects.com/en/3.1.x/intro/
Jinja2는 Python에서 사용되는 템플릿 엔진으로, 현대적이고 디자이너 친화적인 템플릿 언어이다.
Django template에서 영감을 받았으며,
Flask같은 웹 프레임워크에서 HTML 템플릿을 렌더링하는 데 주로 사용되지만 여러 텍스트 파일을 생성하는 데도 사용할 수 있다.
Django template처럼 for문, if문을 활용해 동적인 콘텐츠를 생성할 수 있으며, 변수를 치환하는 표현식을 이용한다.
Jinja2는 어플리케이션 로직이 Python 로직에 모두 속하게 하는 것과
디자이너의 작업이 언어로 인해 제한되지 않도록 하는 것에 중점을 두어 디자인되었다.
설치 방법 :
pip install Jinja2
- Jinja2를 설치하면 MarkupSafe가 함께 설치되는데, 템플릿 렌더링 시 신뢰할 수 없는 입력을 방지해주는 라이브러리이다.
- optional로 Babel을 함께 설치할 수 있는데, 템플릿 번역 지원 기능을 제공한다고 한다.
Jinja API(템플릿 인터페이스 활용) : https://jinja.palletsprojects.com/en/3.1.x/api/
Jinja2의 핵심 모듈에는 Template, Environment, Package Loader가 있다.
Template 클래스 생성자를 사용하면, 문자열로 템플릿을 만들더라도 Template가 자동으로 템플릿을 생성해준다.
Environment는 템플릿 로드 환경을 제공하는데,
대부분의 어플리케이션은 어플리케이션 초기화 시 하나의 Environment 개체를 생성하고, 이를 사용하는 템플릿을 로드하게 된다.
몇몇 경우에, 멀티 환경에서 다른 구성의 템플릿을 유용하게 로드하여 사용할 수 있다.
Package Loader를 사용해 Jinja2를 구성하여 어플리케이션의 템플릿으로 로드하는 것이 가장 간단한 방법이다.
from jinja2 import Environment, PackageLoader, select_autoescape
env = Environment(
loader=PackageLoader("yourapp"),
autoescape=select_autoescape()
)
위 코드가 'yourapp'에 있는 templates 폴더 내의 템플릿들을 찾아 로더와 함께 템플릿 환경을 생성해줄 것이다.
HTML파일에 대한 자동변환도 가능하다.
이 loader는 'yourapp'을 불러오는데에 요구되며, 절대경로를 사용한다.
템플릿을 로드하기 위해 Template를 return해주는 get_template()메서드를 사용한다.
template = env.get_template("mytemplate.html")
몇몇 변수를 불러오기 위해 render()메서드를 사용할 수 있다.
print(template.render(the="variables", go="here"))
get_template()로 가져온 템플릿에 render()메서드를 사용해 특정 변수 불러오기가 가능하다.
단순 문자열을 사용하는 것보다
Template나 Environment.from_string()을 통해 template loader를 사용하는 것이 여러 장점이 있고, 상속도 가능하다고 한다.
Template Desinger 문서(템플릿 언어 활용) : https://jinja.palletsprojects.com/en/3.1.x/templates/
기본적으로 중괄호와 여러 구분기호를 사용하지만 개발자가 구문 구성을 변경할 수 있다.
{% foo %} <% foo %>
기본 Jinja 구분 기호는 다음과 같이 구성됩니다.
- {% ... %} for문, if문 등
- {{ ... }}템플릿 출력으로 인쇄할 표현식
- {# ... #} 템플릿 출력에 포함되지 않은 설명의 경우
영감을 받은 만큼 Django 템플릿 언어와 흡사하다
라인문과 주석도 가능하다.
line_statement_prefix #을 사용해서 for문을 이용할 수 있음!
아래 두 예시는 동등한 결과를 가져온다.
<ul>
# for item in seq ## : 콜론을 붙일 수 있다.
<li>{{ item }}</li>
# endfor ## endfor seq 가독성을 위해 endfor 해당하는 개체를 명시할 수 있다.
</ul>
<ul>
{% for item in seq %}
<li>{{ item }}</li>
{% endfor %}
</ul>
가독성을 위해 for, if, elif문 뒤에 콜론을 붙일 수 있다.
또한 ## 은 ignore되므로 줄바꾸기 기호를 제외하고 줄 끝까지의 모든 내용을 무시한다.
<ul>
# for item in seq ## 주석: seq는 ~~한 객체
...
이외의 것은 공부하면서 상단의 공식 문서를 참고할 것!
아래는 간단 예제
telegram봇에 원하는 형식으로 메세지를 보내기 위해 활용하였는데, 어렵지 않게 원하는 방식으로 동적인 text를 렌더링할 수 있다.
변수를 넣어 test.html 파일을 생성하였다.
<html>
<head>
<title>Hi, It's Jinja. {{title}}</title>
</head>
<body>
<h1>
Hello, {{ name }}
</h1>
<h2>
{{ heading }}
</h2>
<h3>
{{ content }}
</h3>
</body>
</html>
FileSystemLoader로 해당 파일의 경로를 적어 test.html파일을 불러온 후 Environment에 넣어 환경을 설정해준다.
from jinja2 import Environment, FileSystemLoader
# 템플릿에 전달할 데이터
data = {
'title': 'Jinja2 Test',
'heading': 'Jinja2 템플릿 엔진',
'content': '이것은 Jinja2 테스트 예제입니다.',
'name': 'python_bot'
}
# 템플릿 파일이 있는 디렉토리 설정
file_loader = FileSystemLoader('tutorials/Jinja/templates')
jinja_env = Environment(loader=file_loader)
# telegram bot에 넣어주기 위해 함수로 작성
def load_data():
# 템플릿 파일 로드
template = jinja_env.get_template('test.html')
# 템플릿 랜더링
output = template.render(data)
return output
study.py에 작성되어있는 기본 telegram bot의 text에 메시지를 전송할 수 있도록 함수를 입력해주었다.
from telegram.ext import ApplicationBuilder, ContextTypes, CommandHandler
from telegram import Update
import logging
import asyncio
import telegram
import dotenv
# 다른 디렉토리에서 함수를 가져오기 위한 설정
import sys
import os
sys.path.append(os.path.dirname(os.path.abspath(os.path.dirname(os.path.abspath(os.path.dirname(__file__))))))
from tutorials.Jinja.load_template import load_data
async def main():
BOT_TOKEN = dotenv.os.getenv("TELEGRAM_BOT_TOKEN")
CHAT_ID = dotenv.os.getenv("TELEGRAM_CHAT_ID")
bot = telegram.Bot(BOT_TOKEN)
print()
async with bot:
# text에 함수를 입력해준다.
await bot.send_message(text=load_data(), chat_id=CHAT_ID)
if __name__ == '__main__':
dotenv.read_dotenv() # .env에 있는 token과 chat_id를 불러옴
asyncio.run(main()) # 비동기로 bot 실행
실행결과 bot에 텍스트로 보내지다보니,
특정한 템플릿이 필요하지 않다면 템플릿 언어는 빼고 text만 작성하여 전송할 수 있을 것 같다.
템플릿 형식으로 보내는 방법 추가 연구 필요.