시작에 앞서
해당 내용은 <가장 빠른 풀스택을 위한 Flask & FastAPI>, Dave Lee 지음. BJ Public 출판.
내용을 토대로 작성되었습니다. 보다 자세한 사항은 해당 교재를 참고하시기 바랍니다.
이전 내용
템플릿 (Jinja2 패키지)
FastAPI는 Jinja2라는 강력한 템플릿 엔진을 사용하여 HTML 내에서 파이썬 코드를 사용할 수 있게 해준다.
Jinja2 는 FastAPI의 템플릿을 취급할 때 요구되는 중요한 패키지이다.
프런트엔드 개발에 사용되는 기본 기술인 HTML과 CSS는 웹페이지의 구조와 스타일을 정의하는 데 필수적이다.
FastAPI를 사용하기 전에 Jinja2 패키지를 포함한 필요한 패키지들을 설치해야 한다.
pip install jinja2==3.1.2
그리고나서 템플릿 파일들을 보관할 디렉터리를 설정해야 한다. 이 디렉터리는 일반적으로 "templates" 라고 명명되며 HTML 파일들을 이곳에 저장한다.
[프로젝트의 구조]
- main.py: FastAPI 애플리케이션의 메인 코드를 포함하는 파일
- templates 디렉터리: HTML 템플릿 파일들을 저장하는 장소
- index.html: 실제 웹페이지의 구조를 정의하는 HTML 파일
index.html 파일은 아래와 같이 작성하며, {{username}} 을 통해 동적 데이터를 삽입한다. 파이썬 코드에서 설정한 username 변수의 값이 HTML에 반영되어 동적인 웹페이지를 생성하는 데 사용된다.
<!DOCTYPE html>
<html>
<head>
<title>FastAPI Template Example</title>
</head>
<body>
<h1>Hello, {{username}}</h1>
</body>
</html>
▶ FastAPI는 설정된 templates 디렉터리 안에서 index.html 파일을 찾아 해당 파일에 데이터를 채워 넣고, 이를 사용자에게 보여주는 HTML 파일로 랜더링하고, 템플릿 엔진이 HTML 파일과 파이썬 변수를 결합하여 최종적인 웹페이지 생성
FastAPI 설정
[FastAPI 프레임워크에서 Jinja2 템플릿을 사용하기 위해 필요한 설정 작업]
이 설정은 주로 Jinja2Templates 클래스를 이용한다.
1) FastAPI의 fastapi.templating 모듈에서 Jinja2Templates 클래스 임포트 (Jinja2 템플릿 엔진을 FastAPI와 연결해주는 역할)
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
2) FastAPI 애플리케이션 인스턴스 생성 (웹 애플리케이션의 모든 설정과 라우팅 관리)
app = FastAPI()
3) Jinja2Templates 클래스를 이용해서 템플릿 디렉터리 설정 (템플릿 디렉터리: templates 폴더)
templates = Jinja2Templates(directory="templates")
★ Jinja2Templates 클래스의 directory 매개변수의 기본값은 "templates" 이다. 따라서 템플릿 파일에 해당 폴더에 있다면, directory 매개변수를 명시적으로 설젛아지 않아도 된다.
templates = Jinja2Templates()
다만, 명시적으로 디렉터리를 지정하는 것이 코드를 읽는 다른 사람에게 더 명확하게 설정을 전달할 수 있으므로 명시적 설정을 권장한다.
[그외]
templates = Jinja2Templates(directory="custom_folder")
encoding='utf-8", auto_reload=True)
이렇게 설정하면 FastAPI 애플리케이션은 custom_folder 디렉터리를 템플릿 폴더로 사용하고, "utf-8" 인코딩을 적용한 상태로 템플릿을 로드한다. 또한, 템플릿 파일에 변경이 생기면 자동으로 리로드 된다.
- encoding: 템플릿 파일의 인코딩 지정. 기본값은 "utf-8"
- auto_reload: 개발 중에 템플릿 파일이 변경될 경우 자동으로 리로드 여부 설정. 기본값은 None이며, FastAPI 설정에 따라 자동 설정 된다.
템플릿 렌더링
FastAPI 에서 HTML 템플릿에 데이터를 삽입하려면 Jinja2Templates 클래스의 TemplateResponse 메서드를 사용한다.
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/")
def read_root(request: Request):
return templates.TemplateResponse("index.html", {"request": request, "username": "John"{)
[코드 설명]
- Jinja2Templates를 사용해서 templates 객체를 초기화. 이 객체가 "templates" 폴더에 있는 HTML 파일들을 렌더링하는 것을 도와준다.
- read_root 라는 라우터 함수를 정의하고, request:Request 를 매개변수로 설정. FastAPI 가 이 Request 객체를 자동으로 만들어주고, 이 객체는 템플릿으로 전달되어 사용된다.
- FastAPI 에서 tem[lates.TemplateResponse() 메서드를 사용하면 "index.html" 템플릿이 렌더링된다. 이 메서드는 템플릿으로 전달될 변수들을 담은 딕셔너리 {"request": request, "username": "John"} 을 두 번째 인자로 받는다. 특히, TemplateResponse 를 활용할 때는 Request 객체를 딕셔너리에 포함시키는 것이 필수적이다. (FastAPI의 템플릿 시스템이 클라이언트의 HTTP 요청 정보를 포함하는 Request 객체에 의존하기 때문) request 매개변수 외에 username 과 같은 추가 데이터도 이 딕셔너리에 포함시켜 템플릿에 전달할 수 있으며, 이를 통해 템플릿 내에서 동적인 데이터 처리가 가능해진다.
username을 요청에서 받기
FastAPI의 경로 매개변수 또는 쿼리 매개변수를 사용하여 HTTP 요청에서 username을 받아 템플릿에 전달하는 예제 생성
◆ 경로 매개변수 사용 예제
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/user/{username}")
def get_user(request: Request, username: str):
return templates.TemplateResponse("index.html", {"request": request, "username": username})
[테스트]
http://127.0.0.1:8000/user/John 을 방문하게 되면
http://127.0.0.1:8000/user/Jane 을 방문하면
◆ 경로 매개변수 사용 예제
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/user")
def get_user(request: Request, username: str = "John"):
return templates.TemplateResponse("index.html", {"request": request, "username": username})
[테스트]
http://127.0.0.1:8000/user 를 방문하면
만약 URL을 http://127.0.0.1:8000/user?username=Jane 으로 변경하면
이렇게 하면 FastAPI와 Jinja2 템플릿을 사용하여 사용자의 요청에 따라 동적으로 콘텐츠를 변경할 수 있는 웹페이지를 만들 수 있다. 웹브라우저가 다양한 username 값을 테스트해 보면 이 기능의 유용성을 더 잘 느낄 수 있다.
[에러 발생 및 해결방법]
- 디렉터리 확인: Jinja2Templates 의 directory 인자에서 설정한 디렉터리 경로가 올바른지 확인. 경로가 잘못되면 템플릿을 찾을 수 없어 에러 발생.
- 템플릿 파일 이름 확인: TemplateResponse() 함수에서 사용하는 템플릿 파일 이름이 실제로 디렉터리에 존재하는지 확인. 파일 이름이 잘못되면 에러 발생.
FastAPI와 Jinja2의 기본 문법
◆ 변수 출력: {{ variable_name }}
이 문법을 이용하면 파이썬 코드에서 생성한 변수를 HTML 페이지에 쉽게 삽입할 수 있다.
|safe 필터를 사용하면 HTML 태그가 포함된 문자열을 웹페이지에서 안전하게 렌더링할 수 있다.
예) 변수에 저장된 문자열에 HTML 태그가 포함되어 있다면, 그대로 렌더링하고 싶을 때 사용
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/safe")
def get_root_safe(request: Request):
my_variable_with_html: "<h1>Hello, FastAPI!</h1>"
return templates.TemplateResponse("index_with_safe.html", {"request": request, my_variable_with_html})
HTML 코드
<!DOCTYPE html>
<html>
<head>
<title>FastAPI & Jinja2 with safe Filter</title>
</head>
<body>
{{ my_variable_with_html|safe }}
</body>
</html>
▶ 만약 |safe 필터를 사용하지 않는다면 <h1> 태그가 그대로 문자열로 출력되어 웹페이지에 해당 태그가 보이게 된다.
단, |safe 필터는 사용자 입력을 그대로 렌더링할 때 주의가 필요하다. 사용자로부터 받은 데이터를 그대로 렌더링하면 XSS(Cross-Site Scripting)와 같은 보안 문제가 발생할 수 있다.
◆ 주석: {# comment #}
주석; 코드 내에서 설명이나 메모를 남기기 위해 사용하며, 렌더링되지 않아 사용자에게는 보이지 않는다.
HTML 코드 예시
<!DOCTYPE html>
<html>
<head>
<title>FastAPI & Jinja2</title>
</head>
<body>
{{ my_variable }}
{#
이것은 주석이며,
이 부분은 렌더링 되지 않는다.
또한, 여러 줄로 확장할 수 있다.
#}
</body>
</html>
FastAPI 코드
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/")
def read_root(request: Request):
return templates.TemplateResponse("index.html", {"request": request, "my_variable": "Hello, FastAPI!"})
[테스트]
http://127.0.0.1:8000/ 접속하면 주석은 렌더링되지 않으므로, "Hello, FastAPI!" 만 나타난다.
◆ 제어문 외 (if, else, elseif 등)
- 제어문 - {% if... %} ... {% endif %}: 제어문을 사용하면 렌더링되는 HTML 콘텐츠를 동적으로 변경할 수 있다. Jinja2의 제어문은 FastAPI 코드에서 받은 변수의 값을 기반으로 HTML 을 조건적으로 렌더링하는 데 사용한다.
- if문: {% if... %} ... {% endif %}
- else문: {% else %}...
- elseif문: {% elif ... %} ...
FastAPI 코드 예시
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/greet")
def greeting(request: Request, time_of_day: str):
return templates.TemplateResponse("index.html", {"request": request, "time_of_day": time_of_day})
HTML 코드 예시
<!DOCTYPE html>
<html>
<head>
<title>FastAPI & Jinja2 with Control Statements</title>
</head>
<body>
{% if time_of_day == "morning" %}
<h1>Good Morning!</h1>
{% elif time_of_day == "afternoon" %}
<h1>Good Afternoon!</h1>
{% else %}
<h1>Good Evening!</h1>
{% endif %}
</body>
</html>
[테스트 방법]
http://127.0.0.1:8000/greet?time_of_day=morning 으로 접속
http://127.0.0.1:8000/greet?time_of_day=afternoon
http://127.0.0.1:8000/greet?time_of_day=evening
◆ 반복문: {% for item in items %}... {% endfor %}
반복문은 Jinja2에서 동적으로 여러 요소를 렌더링할 때 자주 사용된다. FastAPI 에서 파이썬 리스트나 다른 반복 가능한 객체를 HTML 템플릿에 전달할 수 있고, Jinja2의 {% for %} 구문을 사용하여 이러한 요소를 렌더링할 수 있다.
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/items")
def read_items(request: Request):
my_items = ["apple", "banana", "kiwi"]
return templates.TemplateResponse("index.html", {"request": request, "items": my_items})
HTML 코드
<!DOCTYPE html>
<html>
<head>
<title>FastAPI & Jinja2 with For Loop</title>
</head>
<body>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
[코드 설명]
- 파이썬 코드는 my_items 리스트 생성
- 이 리스트를 items 라는 이름으로 HTML 템플릿에 전달
- HTML 에서는 {% for item in items %}와 {% endfor %} 태그를 사용하여 리스트의 각 요소를 <li> 태그로 렌더링
[테스트]
http://127.0.0.1:8000/items
이렇게 반복문을 활용하면 동적인 데이터를 쉽고 효과적으로 렌더링할 수 있다.
★ 리스트를 직접 요청으로 받아서 출력
(문자열로 받은 데이터를 콤마 기준으로 내부에서 리스트로 생성)
from fastapi import FastAPI, Request
from fastapi.templating import Jinja2Templates
from typing import List
app = FastAPI()
templates = Jinja2Templates(directory="templates")
@app.get("/dynamic_items/")
def dynamic_items(request: Request, item_list: str = ""):
items = item_list.split(",")
return templates.TemplateResponse("index.html", {"request": request, "items": items})
HTML 코드
<!DOCTYPE html>
<html>
<head>
<title>FastAPI & Jinja2 with Dynamic List</title>
</head>
<body>
<ul>
{% for item in items %}
<li>{{ item }}</li>
{% endfor %}
</ul>
</body>
</html>
[테스트]
http://127.0.0.1:8000/dynamic_items/?item_list=candy,snack,chocolate 으로 접속하면
쿼리 매개변수로 전달한 값이 HTML 페이지에 렌더링된다.
또한, 쿼리 매개변수를 여러 번 사용하여 리스트를 전달할 수 있다.
다음 내용
'[파이썬 Projects] > <파이썬 웹개발>' 카테고리의 다른 글
[파이썬] FastAPI - FastAPI와 Jinja2 고급 문법 (0) | 2024.08.22 |
---|---|
[파이썬] FastAPI - 예외 처리(exception handling) (0) | 2024.08.20 |
[파이썬] FastAPI - 요청 (0) | 2024.08.20 |
[파이썬] FastAPI - 응답 클래스 (0) | 2024.08.19 |
[파이썬] FastAPI - 응답 모델 (0) | 2024.08.18 |