大丈夫なパターン

htmlファイルのあるフォルダと関数Jinja2Templatesを呼び出すpythonファイルが同一階層の場合は出現しません。

testapp
├ app.py
└ templates
  └ index.html
from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from fastapi.requests import Request

app = FastAPI()
templates = Jinja2Templates(directory='templates')

@app.get("/", response_class=HTMLResponse)
def index(request:Request):
    return templates.TemplateResponse(
            "index.html", {"request": request)
			)

エラーが出るパターン

htmlファイルのあるフォルダと関数Jinja2Templatesを呼び出すpythonファイルが同一階層に無い場合にエラーが出現します。

testapp
 ├ router
 │ └ route.py
 ├ templates
 │ └ index.html
 └ main.py
from fastapi import FastAPI

from .router import route

app = FastAPI()
app.include_router(route.router)
from fastapi import APIRouter
from fastapi.templating import Jinja2Templates
from fastapi.responses import HTMLResponse
from fastapi.requests import Request

router = APIRouter()
templates = Jinja2Templates(directory='../templates') #ここが問題点!


@router.get("/", response_class=HTMLResponse)
def index(request:Request):
    return templates.TemplateResponse(
            "index.html",{"request": request}
            )

エラーが出ますね

Traceback (most recent call last):
"""
"""
jinja2.exceptions.TemplateNotFound: index.html

解決策

rendererファイルにtemplatesファイルを格納し、_init_.pyを追加します。

testapp
├ renderer
│ ├ __init__.py
│ └ templates
│   └ index.html
├ router
│ └ route.py
└ main.py

main.pyは変わりません。

router/route.pyではテンプレートエンジンを作成せず、新しく作ったディレクトリrendererよりエンジンをインポートします。

from fastapi import APIRouter
from fastapi.responses import HTMLResponse
from fastapi.requests import Request

from renderer import loader #rendererからテンプレートエンジンを読み込む

router = APIRouter()

@router.get("/", response_class=HTMLResponse)
def index(request:Request):
    template = loader.get_template('index.html')
    return template.render(request=request)

renderer/__init__.pyではテンプレートフォルダを指定しエンジンを作成します。

from jinja2 import Environment, PackageLoader, select_autoescape

loader = Environment(
    loader=PackageLoader('renderer', 'templates'),
    autoescape=select_autoescape(['html', 'xml'])
)

これで実行できます。

テンプレートに変数を埋め込むときは関数template.render()に引数を追加します。例えばindex.htmlに{{name}}と書き込み、変数nameを埋め込む場合はtemplate.render(name="hogehoge")と書き込めます。

参考

テンプレートエンジンとは何か?Jinja2の基本3

コード

github