fasthx:FastAPI+HTMX正确的入门方法


FastAPI 和 HTMX,正确的方法。

主要特征:

  • 正如人们所期望的那样,装饰器语法可以与 FastAPI 一起使用,无需在路由中使用未使用或神奇的依赖项。
  • 可与任何模板引擎或服务器端渲染库一起使用,例如markyp-html或dominate.
  • 内置Jinja2 模板支持(即使有多个模板文件夹)。
  • 使渲染引擎能够访问修饰路由的所有依赖项。
  • 如果FastAPI路由收到非 HTMX请求,默认情况下将保持正常工作,因此同一路由可以同时提供数据和渲染 HTML。
  • 正确的类型可以将其他(类型化)装饰器应用到您的路由中。
  • 适用于同步和异步路由。

该软件包在 PyPI 上可用,可以通过以下方式安装:

$ pip install fasthx

Jinja2 模板
要开始服务 HTMX 请求,您所需要做的就是创建一个实例fasthx.Jinja并将其用作路由上的装饰器,如下所示:

from fastapi import FastAPI
from fastapi.templating import Jinja2Templates
from fasthx import Jinja

# Create the app.
app = FastAPI()

创建一个 FastAPI Jinja2Templates 实例,并用它来创建一个作为装饰器的 FastHX Jinja 实例。
jinja = Jinja(Jinja2Templates("templates"))

@app.get(
"/htmx-or-data")
@jinja(
"user-list.html")  # 使用 user-list.html 模板渲染响应。
def htmx_or_data() -> dict[str, list[dict[str, str]]]:
    return {
"users": [{"name": "Joe"}]}

@app.get(
"/htmx-only")
@jinja.template(
"user-list.html", no_data=True)  # 使用 user-list.html 模板渲染响应。
def htmx_only() -> dict[str, list[dict[str, str]]]:
    # no_data is set to True, so this route can not serve JSON, it only responds to HTMX requests.
    return {
"users": [{"name": "Joe"}]}


自定义模板
自定义模板Jinja通过允许访问渲染器函数的修饰路由的所有依赖项,提供了比内置渲染器更大的灵活性:

from typing import Annotated, Any

from fastapi import Depends, FastAPI, Request
from fasthx import hx

# Create the app.
app = FastAPI()

# 创建依赖项,查看其返回值是否可在呈现函数中使用。
def get_random_number() -> int:
    return 4  # Chosen by fair dice roll.

DependsRandomNumber = Annotated[int, Depends(get_random_number)]


# 如果使用静态类型检查器,"result "的类型提示必须与使用该呈现方法的路由的返回类型
注释相匹配
def render_user_list(result: list[dict[str, str]], *, context: dict[str, Any], request: Request) -> str:
    # The value of the `DependsRandomNumber` dependency is accessible with the same name as in the route.
    random_number = context[
"random_number"]
    lucky_number = f
"<h1>{random_number}</h1>"
    users =
"".join(("<ul>", *(f"<li>{u['name']}</li>" for u in result), "</ul>"))
    return f
"{lucky_number}\n{users}"

@app.get(
"/htmx-or-data")
@hx(render_user_list)
def htmx_or_data(random_number: DependsRandomNumber) -> list[dict[str, str]]:
    return [{
"name": "Joe"}]

@app.get(
"/htmx-only")
@hx(render_user_list, no_data=True)
async def htmx_only(random_number: DependsRandomNumber) -> list[dict[str, str]]:
    return [{
"name": "Joe"}]

唯一依赖项是fastapi