
템플릿 엔진은 미리 정의된 템플릿(HTML, XML 등)에 동적으로 데이터를 결합하여 최종적으로 사용자에게 제공될 HTML 등의 출력물을 생성하는 도구입니다. 이를 통해 정적인 HTML 파일을 유지하면서도 데이터베이스에서 가져온 내용을 삽입하여 동적인 웹 페이지를 쉽게 생성할 수 있습니다.
템플릿 엔진을 사용하면 프레젠테이션(뷰)과 비즈니스 로직을 분리할 수 있어 코드의 유지보수성과 재사용성이 향상됩니다. 또한 조건문, 반복문, 변수 치환, 필터, 매크로 등 다양한 기능을 제공하여 동적인 데이터를 효과적으로 관리하고 표현할 수 있습니다.
Jinja2는 Python 기반의 강력한 템플릿 엔진으로, HTML 등의 템플릿을 작성하고 렌더링하는 기능을 제공합니다. 그러나 Jinja2 자체는 특정 웹 프레임워크와 직접적인 연동 기능을 제공하지 않으므로, FastAPI와 함께 사용할 경우 별도의 설정이 필요합니다.
예를 들어, Environment, Loader, autoescape 등 모든 설정을 직접 정의해야 합니다. 개발자는 템플릿이 저장된 디렉토리를 지정하고, 자동 이스케이프 여부를 설정하며, 필요한 경우 사용자 정의 필터를 추가하는 등의 작업을 수행해야 합니다.
Jinja2Templates는 FastAPI에서 Jinja2를 더욱 쉽게 활용할 수 있도록 설계된 헬퍼(wrapper) 클래스입니다. Jinja2의 기능을 내부적으로 활용하면서, FastAPI와의 통합을 간편하게 만들어주는 역할을 합니다.
즉, Jinja2Templates는 FastAPI 환경에서 Jinja2를 보다 효율적으로 사용할 수 있도록 기능을 확장한 도구라고 할 수 있습니다.
내부적으로는 Jinja2의 Environment 객체를 생성하고 사용하기 때문에, Jinja2의 모든 기능을 그대로 활용할 수 있습니다. 실제로 templates.env를 통해 Jinja2의 Environment에 접근할 수 있으며, 이를 이용해 커스터마이징이 가능합니다.
다음과 같은 기능을 수행할 수 있습니다:
TemplateResponse를 활용하여 FastAPI에서 직접 HTML 응답을 제공합니다.url_for을 템플릿에서 바로 사용할 수 있어 동적 URL 생성을 간편하게 처리할 수 있습니다.Jinja2Templates를 활용하면 FastAPI에서 템플릿 기반 웹 애플리케이션을 보다 효율적으로 개발할 수 있으며, 설정의 간소화 및 유연한 커스터마이징이 가능합니다.
템플릿 폴더 지정: HTML 파일 등이 위치한 폴더(예: templates/)를 준비합니다.
Jinja2Templates 인스턴스 생성:
from fastapi.templating import Jinja2Templates
templates = Jinja2Templates(directory="templates")
템플릿 렌더링: FastAPI 엔드포인트에서 TemplateResponse를 사용해 템플릿을 렌더링합니다.
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.get("/", response_class=HTMLResponse)
async def read_root(request: Request):
return templates.TemplateResponse("templates/index.html", {"request": request, "message": "Hello, World!"})
템플릿 내부 작성: Jinja2 문법을 활용해 동적 데이터 렌더링이 가능하며, 변수 삽입, 제어문 등이 지원됩니다.
이와 같이 기본 설정과 사용법을 통해 간단하게 템플릿 렌더링이 가능합니다.
FastAPI에서는 템플릿 렌더링 시 반드시 {"request": request, ...}와 같이 request 객체를 포함시켜야 합니다.
이를 통해 URL 생성이나 기타 컨텍스트 기능을 올바르게 사용할 수 있습니다.
템플릿 구조 설계 시, 공통 레이아웃이나 헤더, 푸터 등 반복되는 요소는 Base Template으로 만들고 개별 페이지에서는 이를 상속하여 재사용성을 높이는 방식이 일반적입니다.
이와 유사하게, 반복되는 템플릿 코드가 있다면 Jinja2의 매크로(Macro) 기능을 활용하여 보다 효율적으로 사용할 수 있습니다.
예를 들어, 블로그 게시글에서 카드 스타일(Post Card)을 반복적으로 렌더링할 경우, 다음과 같이 매크로를 정의할 수 있습니다:
{% macro render_post(title, author, date, content) %}
<div class="post-card">
<h2>{{ title }}</h2>
<p><strong>{{ author }}</strong> - {{ date }}</p>
<p>{{ content }}</p>
</div>
{% endmacro %}
템플릿 내에서 매크로를 호출하면 개별 블로그 게시글을 효율적으로 렌더링할 수 있습니다:
{{ render_post('FastAPI 시작하기', '홍길동', '2024-02-16', 'FastAPI는 빠르고 강력한 웹 프레임워크입니다.') }}
매크로는 별도의 템플릿 파일에서 정의하고 이를 import하여 사용할 수도 있습니다. 이를 통해 공통으로 사용되는 템플릿 코드를 한 곳에 모아두고 여러 템플릿에서 재사용할 수 있습니다.
macros.html 파일
{% macro render_button(label, url) %}
<a href="{{ url }}" class="btn">{{ label }}</a>
{% endmacro %}
템플릿에서 import 후 사용
{% import 'macros.html' as macros %}
{{ macros.render_button('자세히 보기', '/details') }}
이렇게 하면 DRY(Don't Repeat Yourself) 원칙을 지키면서 템플릿 코드의 가독성과 유지보수성을 향상시킬 수 있습니다.
컨텍스트 프로세서를 활용하면 템플릿에서 모든 페이지에서 공통적으로 사용할 변수를 자동으로 제공할 수 있습니다. 이를 통해 템플릿마다 동일한 변수를 수동으로 전달할 필요 없이, 전역적으로 데이터를 공유할 수 있습니다.
def global_context(request: Request):
return {"app_name": "My FastAPI App", "user_ip": request.client.host}
templates = Jinja2Templates(directory="templates", context_processors=[global_context])
<h1>Welcome to {{ app_name }}!</h1>
<p>Your IP: {{ user_ip }}</p>
컨텍스트 프로세서를 활용하면 전역적으로 사용할 데이터를 한 번만 정의하면 되므로 유지보수가 쉬워지고, 코드의 중복이 줄어듭니다.
Jinja2에서는 사용자 정의 필터(Custom Filters)를 등록하여 템플릿 내 데이터를 변환하거나 가공할 수 있습니다. 기본적으로 제공되는 필터(예: upper, lower, safe 등) 외에도 커스텀 필터를 직접 정의하여 특정 데이터 변환 로직을 쉽게 적용할 수 있습니다.
from datetime import datetime
def format_date(value, format="%Y-%m-%d"):
return value.strftime(format)
templates.env.filters["format_date"] = format_date
<p>오늘 날짜: {{ today | format_date("%B %d, %Y") }}</p>
커스텀 필터를 활용하면 템플릿 내에서 Python 코드 없이도 데이터를 변환하여 출력할 수 있어, 유지보수성과 가독성이 향상됩니다.
Jinja2는 템플릿을 컴파일하여 캐싱하는 기능을 제공하여 렌더링 속도를 최적화할 수 있습니다. 이를 통해 자주 사용되는 템플릿을 캐싱하여 불필요한 컴파일 비용을 줄일 수 있습니다.
templates.env.cache_size = 50 # 최대 50개의 템플릿을 캐싱
templates = Jinja2Templates(directory="templates", trim_blocks=True, lstrip_blocks=True)
공백 제거 옵션을 활성화하면 템플릿의 불필요한 공백을 줄여 렌더링 속도를 개선할 수 있습니다.
Jinja2는 기본적으로 동기(Synchronous) 엔진이며, await을 지원하지 않습니다. 하지만 FastAPI는 비동기(Async) 웹 프레임워크이므로, 비동기 엔드포인트에서 Jinja2를 활용하려면 몇 가지 고려해야 할 사항이 있습니다.
@app.get("/async", response_class=HTMLResponse)
async def async_page(request: Request):
return templates.TemplateResponse("async_page.html", {"request": request})
비동기 작업이 필요한 경우, 템플릿 렌더링 자체는 동기적으로 처리하고, 데이터 처리 부분을 비동기로 실행하는 방식이 일반적입니다.
Jinja2Templates는 FastAPI에서 서버 사이드 렌더링(SSR)을 수행할 수 있도록 도와주는 강력한 도구입니다. 이를 활용하면 동적 데이터를 포함한 HTML을 효율적으로 생성할 수 있으며, 템플릿 구조를 잘 설계하면 코드의 유지보수성과 재사용성을 극대화할 수 있습니다.
이 글에서는 Jinja2Templates의 개념과 기본 설정, 그리고 실전 활용법을 다루었습니다. 특히, 매크로(Macro)를 활용한 코드 재사용, 컨텍스트 프로세서를 통한 전역 변수 관리, 커스텀 필터 적용, 템플릿 캐싱 및 성능 최적화, 비동기 FastAPI 엔드포인트에서의 활용 등 핵심적인 주제를 살펴보았습니다.
Jinja2Templates를 효과적으로 활용하면, FastAPI 기반의 웹 애플리케이션에서 빠르고 안전한 서버 사이드 렌더링을 구현할 수 있습니다. 또한, 템플릿 엔진의 다양한 기능을 활용하여 코드를 더욱 모듈화하고 가독성을 높이며, 개발 생산성을 향상시킬 수 있습니다.