关于 htmx-patterns
面向 Django 开发的 HTMX 模式指南,帮助实现服务器渲染的动态界面。内容涵盖局部模板、请求检测、表单反馈和错误处理。
主要功能
- 01HTMX 请求检测与响应
- 02局部模板组织规范
- 03表单验证与反馈模式
- 04响应头驱动的页面行为
- 05加载状态与错误处理
适用场景
- 01为 HTMX 请求返回局部 HTML
- 02构建渐进增强的 Django 页面
- 03处理表单提交与验证错误
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ waldencui/ claude-code-django --skill htmx-patterns安装后在 Claude Code 中输入/htmx-patterns确认已加载。
详细介绍
Django 的 HTMX 模式
核心理念
- 由服务器渲染 HTML,而非 JSON——HTMX 请求返回 HTML 片段,而非数据
- 使用局部模板进行动态更新——为 HTMX 响应单独创建
_partial.html文件 - 渐进增强——页面无需 JavaScript 也能正常工作,HTMX 则提升用户体验
- 尽量减少客户端复杂度——让服务器承担繁重工作
关键提示与提醒
用户体验最佳实践
始终包含加载指示器
- 使用
hx-indicator在请求期间显示加载状态 - 用户不应疑惑自己的操作是否生效
- 示例:
<button hx-get="/data/" hx-indicator="#spinner">Load</button>
始终向用户提供反馈
- 使用 Django 消息框架反馈成功或错误信息
- 在 HTMX 响应中返回错误消息,不要静默失败
- 操作完成后显示结果
妥善处理错误
- 返回正确的 HTTP 状态码(验证错误使用 400,服务器错误使用 500)
- 在局部模板中渲染表单错误
- 不要吞掉异常——记录日志并向用户显示易于理解的消息
Django 专用模式
始终检测 HTMX 请求
- 检查
request.headers.get("HX-Request")以检测 HTMX 请求 - HTMX 请求返回局部模板,其他请求返回完整页面模板
- 模式:
if request.headers.get("HX-Request"): return render(request, "_partial.html", context)
HTMX 请求始终返回局部模板
- HTMX 请求应返回
_partial.html模板,而非包含base.html的完整页面 - 对 HTMX 请求返回完整页面会破坏用户体验并发送重复的 HTML
- 局部模板应为自包含的 HTML 片段
始终验证 request.method
- 处理表单数据前检查
request.method == "POST" - 返回正确的状态码(方法错误时返回 405 Method Not Allowed)
CSRF 已在全局配置
- 基础模板的
<body>上已设置hx-headers——无需在各个表单中添加 CSRF 令牌 - 所有 HTMX 请求都会自动包含 CSRF 令牌
模板组织
命名约定
- 局部模板:
_partial.html(以下划线开头) - 完整页面:
page.html(不加前缀) - 示例:
posts/list.html(完整页面)包含posts/_list.html(局部模板)
结构
- 完整页面模板继承
base.html并包含局部模板 - 局部模板只包含动态 HTML 片段
- HTMX 的目标指向局部模板所在的容器 div
让局部模板各司其职
- 每个局部模板应表示一个逻辑上的 UI 组件
- 避免局部模板过于庞大或承担过多职责
- 将多个较小的局部模板组合成较大的 UI
Django 视图模式
HTMX 检测
检查 HX-Request 标头以检测 HTMX 请求:
def my_view(request):
context = {...}
if request.headers.get("HX-Request"):
return render(request, "app/_partial.html", context)
return render(request, "app/full_page.html", context)
表单处理模式
要点:
- 按常规方式验证表单
- 成功时:返回包含新数据的局部模板,或触发客户端事件
- 出错时:返回包含表单错误的局部模板
- 始终同时处理 HTMX 和非 HTMX 情况
def create_view(request):
if request.method == "POST":
form = MyForm(request.POST)
if form.is_valid():
obj = form.save()
if request.headers.get("HX-Request"):
return render(request, "app/_item.html", {"item": obj})
return redirect("app:list")
# Return form with errors
if request.headers.get("HX-Request"):
return render(request, "app/_form.html", {"form": form})
else:
form = MyForm()
return render(request, "app/create.html", {"form": form})
响应标头参考
HTMX 会根据特殊响应标头执行客户端行为:
HX-Trigger
在响应后触发客户端事件
- 用途:操作后更新页面的其他部分
- 示例:
response["HX-Trigger"] = "itemCreated" - 模板监听:
<div hx-get="/count/" hx-trigger="itemCreated from:body">
HX-Redirect
客户端重定向
- 用途:操作成功后重定向
- 示例:
response["HX-Redirect"] = reverse("app:detail", args=[obj.pk])
HX-Retarget / HX-Reswap
从服务器覆盖 hx-target 和 hx-swap
- 用途:为成功和错误情况指定不同的目标
- 成功:
response["HX-Retarget"] = "#main" - 错误:返回局部模板但不更改目标(目标仍为表单)
HX-Refresh
强制刷新整个页面
- 用途:发生影响整个页面的重大状态变更时
- 示例:
response["HX-Refresh"] = "true"
常见问题
- 缺少加载指示器:始终使用
hx-indicator——没有反馈时,用户会多次点击 - 在 HTMX 响应中返回完整页面:返回
_partial.html,而不是带有base.html的完整页面——检查HX-Request请求头 - 未处理表单错误:验证失败时始终返回带有错误信息的表单,而不只是处理成功的情况
- 未禁用按钮:使用
hx-disabled-elt="this"防止重复提交 - N+1 查询:HTMX 视图和常规视图一样,需要使用
select_related()/prefetch_related()
与其他技能的集成
- django-templates:局部模板组织和继承模式
- django-forms:HTMX 表单提交和验证
- django-extensions:使用
show_urls验证 HTMX 端点 - pytest-django-patterns:测试 HTMX 端点和请求头
- systematic-debugging:调试 HTMX 请求/响应问题
评论
支持 Markdown