본문 바로가기
FastAPI tips

Jinja2 템플릿 활용

by 스티브 십잡스 2024. 5. 8.

1) style.css 파일 적용

from fastapi.staticfiles import StaticFiles
from fastapi import FastAPI


app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
  • FastAPI가 초기화된 위치를 기준으로 /static 폴더의 경로를 설정한다.
  • html 코드 내에서 아래와 같이 호출이 가능하다.
    • <link href="{{ url_for('static', path='/css/style.css') }}" rel="stylesheet" type="text/css" id="cssLink"/>

 

2) Jinja2Template 예제

from pathlib import Path
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from fastapi import APIRouter, Request
import json


BASE_DIR = Path(__file__).resolve().parent.parent.parent

templates = Jinja2Templates(directory=BASE_DIR / "templates")

router = APIRouter()

@router.get(
    "/url",
    response_class=HTMLResponse,
)
async def jinja2_template_example(request: Request):
    form_data = await request.form()
    return templates.TemplateResponse('./index.html', {
        "request": request,
        "json_data": json.dumps(form_data._dict, ensure_ascii=False),
    })
  • index.html은 해당 파일 기준으로 BASE_DIR / templates 폴더 안에 존재한다.
  • “request”: request는 필수이며, html에 넘겨줄 데이터를 key-value 구조로 넘긴다.
    • html 태그 안에서 "{{ key }}" 로 클라이언트가 넘겨준 데이터를 확인할 수 있다.
    • json_data를 넘기면, <script> 안에서 데이터 처리를 해줘야 한다. (개인적으로 비선호)
      // script 태그 안에서 데이터 처리
      var tempParams = document.getElementById('json_data').innerHTML;
      tempParams = JSON.parse(tempParams);
      
      /*
          콤마, &, ;, \n, \, |, ', ", <
          특수 문자는 포함되면 안됨.
      */
      for (var key in tempParams) {
          var hiddenField = document.createElement("input");
          hiddenField.setAttribute("type", "hidden");
          hiddenField.setAttribute("name", key);
          hiddenField.setAttribute("value", tempParams[key].replace("&amp;", "&"));
          document.form_auth.appendChild(hiddenField); 
      }
      
      ...
      
      // body에 이렇게 태그를 선언해둬야 한다.
      <body oncontextmenu="return false;" ondragstart="return false;" onselectstart="return false;">
          <form name="form_auth" method="post">
              <div id="sbParam" style="display: none;">{{ sbParam }}</div>         
         </form>
      </body>​
    • form_data에서 데이터를 하나 하나 꺼내서 넘기는 것을 개인적으로는 선호한다.
      • 아래 예제를 예시로 들면, "tid": form_data['tid]
  • 외부 결제 연동 시, 예제 템플릿
    <!DOCTYPE html>
    <html>
    <head>
        <title>Jinja2</title>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    
        <script language="javascript">
            // Function to submit form
            window.onload=function() {
                function submit() {
                    var sendfrm = document.getElementById("SendForm_id");
                    sendfrm.action = return_url;
                    sendfrm.submit();
                }
    
                let return_url = "{{ returnUrl }}";	// 내부 API 또는 Front url
    
                submit();
            }
        </script>
    </head>
    <body>
        <form id="SendForm_id" name="SendForm" method="POST">
            <input type="hidden" class="input" style="width: 100%; color: gray;" name="mid" value="{{ mid }}" readOnly><br />
            <input type="hidden" class="input" style="width: 100%;" name="payUserKey" value="{{ payUserKey }}" readOnly><br />
            <input type="hidden" class="input" style="width: 100%;" name="tid" value="{{ tid }}" readOnly><br />
        </form>
    </body>
    </html>
    • returnUrl을 통해 내부적인 로직을 더 타거나 마지막에 프론트 화면으로 리다이렉트시킨다.

 

 

3) 스크립트 리턴

from fastapi.responses import HTMLResponse
from jinja2 import Template


def invalid_error(resultMsg: str = ""):
    return_url = f"{RETURN_HOST}/order"  # 프론트 주소
    
    template_str = """
        <script>
            function result_error() {   
                alert('{{ resultMsg }}');
                window.opener.postMessage('paymentError', '{{ return_url }}');
                window.close();
            }
            result_error();
        </script>
    """
    template = Template(template_str)
    rendered_template = template.render(resultMsg=resultMsg, return_url=return_url)
    return rendered_template
    
@router.post(
    "/url",
    response_class=HTMLResponse,
)
def example(request: Request):
    return invalid_error()
  • 에러가 발생한 경우, html script 코드를 리턴해서 에러 처리를 할 수 있다.

'FastAPI tips' 카테고리의 다른 글

Excel 다운로드 API  (0) 2024.05.08
Middleware 커스텀해서 사용하기  (0) 2024.05.03
UploadFile, 이미지 form-data  (0) 2024.03.28
Request에서 form-data, query-string 가져오기  (0) 2024.03.28