【FastAPI】テンプレートエンジンを使ってHTML・CSSを配信

FastAPI
を使用してJSON
ではなく、テンプレートエンジンを用いてHTML
やCSS
を返す方法をご紹介いたします。


FastAPIの基礎についての記事まとめ
テンプレートエンジン
テンプレートエンジンはjinja
を用います。
jinja2
とは「python用の、htmlを動的作成できるテンプレートエンジン」です。
django
やflask
でも用いられている一般的なもので、データベースの値を埋め込んだり、if
やfor
文などもテンプレートに埋め込めます。
https://jinja.palletsprojects.com/en/3.0.x/
例えば、下記のようにhtml
ファイルを記述できます。
<h1>Hello {{ name }}</h1>
{% if name %} is_name {% endif %}
{% for object in object_list %}
{{ object }}
{% endfor %}
pip install jinja2
テンプレートの作成
まずは、テンプレート用のディレクトリを作成します。
ここでは、templates/
とします。ここにhtml
やcss
ファイルを保管していきます。
Jinja2Templatesとは?
router/templates.py
にJinja2Templates
のインスタンスを作成します。
from fastapi.templating import Jinja2Templates
~~~
templates = Jinja2Templates(directory='templates')
先程作成したtemplates
ディレクトリを指定しています。
簡単なエンドポイントの作成
まずは基本的なエンドポイントから作成します。
response_class
にはHTMLResponse
を指定しており、返り値には
product.html
- テンプレートに渡す値
を渡しています。

from fastapi.responses import HTMLResponse
from fastapi.requests import Request
~~~
@router.get("/products/{id}", response_class=HTMLResponse)
def get_product(id: str, request: Request):
return templates.TemplateResponse(
"product.html",
{
"request": request,
"id": id
}
)
product.html
には下記のような簡単なhtml
を作成しました。
<div>Product ID is {{ id }}</div>
{{ id }}
はテンプレートタグと呼ばれており、返り値のid
に対応しています。
https://jinja.palletsprojects.com/en/3.0.x/templates/
確認してみましょう。

Response body
の値を確認すると、無事値が埋め込まれていることが確認できました。
POSTされた値を利用
より実践的な内容で、POST
で受け取ったから値をテンプレートに記述してみます。
まずは、schemas.py
を作成してBaseModel
の型を作成します。


from pydantic import BaseModel
class ProductBase(BaseModel):
title: str
description: str
price: float
りクエストボディの型を作成し、受け取った値をテンプレートに記述できるように追加しました。
@router.post("/products/{id}", response_class=HTMLResponse)
def get_product(id: str, product: ProductBase ,request: Request):
return templates.TemplateResponse(
"product_post.html",
{
"request": request,
"id": id,
"title": product.description,
"price": product.price
}
)
指定したhtml
ファイルの中身は下記になります。
<div>
<li>id : {{ id }}</li>
<li>title : {{ title }}</li>
<li>price : {{ price }}</li>
</div>
実際にAPI
を確認してみましょう。

うまく反映されていますね。

テンプレートの値は、下記の様にまとめることも可能です。
@router.post("/products/{id}", response_class=HTMLResponse)
def get_product(id: str, product: ProductBase ,request: Request):
return templates.TemplateResponse(
"product_post.html",
{
"request": request,
"id": id,
"product": product
}
)
<div>
<li>id : {{ id }}</li>
<li>title : {{ product.title }}</li>
<li>price : {{ product.price }}</li>
</div>
CSSファイルなどの静的ファイルの配信
html
ファイルだけではなくcss
ファイルも一緒に配信するには静的ファイルを配信できるようにします。

main.py
にtemplates/static
以下を配信できるように設定しました。
from fastapi.staticfiles import StaticFiles
~~~
app.mount(
'/templates/static',
StaticFiles(directory="templates/static"),
name='static'
)
templates/static
配下にcss
ファイルを作成して反映させてみましょう。
product_post.html
とproduct.css
を編集します。
<head>
<link rel="stylesheet" href="{{ url_for('static', path='/product.css') }}">
</head>
<div class="list">
<li>id : {{ id }}</li>
<li>title : {{ product.title }}</li>
<li>price : {{ product.price }}</li>
</div>
href=
にはファイルパスを指定しています。
.list {
background-color: red;
}
実際に確認します。

受けとったレスポンスを確認してみましょう。CSSが反映されていればOKです。
htmlのプレビューは下記サイトで行いました。
https://htmledit.squarefree.com/

無事反映されていますね!
この他にもデータベースの値を持ってきたり、テンプレート内でfor
文やif
文での処理も可能です。
データベースとの連携も、CRUD
処理での値を持ってくるだけです。


FastAPIの基礎についての記事まとめ
コメント