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

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

この記事のサンプルコード

目次

テンプレートエンジン

テンプレートエンジンはjinjaを用います。

jinja2とは「python用の、htmlを動的作成できるテンプレートエンジン」です。

djangoflaskでも用いられている一般的なもので、データベースの値を埋め込んだり、iffor文などもテンプレートに埋め込めます

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 %}

jinja2のインストールが必要です。

pip install jinja2

テンプレートの作成

まずは、テンプレート用のディレクトリを作成します。

ここでは、templates/とします。ここにhtmlcssファイルを保管していきます。

Jinja2Templatesとは?

router/templates.pyJinja2Templatesのインスタンスを作成します。

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.pytemplates/static以下を配信できるように設定しました。

from fastapi.staticfiles import StaticFiles

~~~

app.mount(
    '/templates/static', 
    StaticFiles(directory="templates/static"), 
    name='static'
    )

templates/static配下にcssファイルを作成して反映させてみましょう。

product_post.htmlproduct.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=にはファイルパスを指定しています。

flaskのチュートリアルページが分かりやすいです→コチラ

.list {
  background-color: red;
}

実際に確認します。

受けとったレスポンスを確認してみましょう。CSSが反映されていればOKです。

htmlのプレビューは下記サイトで行いました。

https://htmledit.squarefree.com/

無事反映されていますね!

この他にもデータベースの値を持ってきたり、テンプレート内でfor文やif文での処理も可能です。

データベースとの連携も、CRUD処理での値を持ってくるだけです。

この記事のサンプルコード

この記事が気に入ったら
フォローしてね!

よかったらシェアしてね!

コメント

コメントする

目次
閉じる