htmx-patterns
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHTMX Patterns for Django
用于 Django 的 HTMX 模式
Core Philosophy
核心理念
- Server renders HTML, not JSON - HTMX requests return HTML fragments, not data
- Partial templates for dynamic updates - separate files for HTMX responses
_partial.html - Progressive enhancement - pages work without JavaScript, HTMX enhances UX
- Minimal client-side complexity - let the server do the heavy lifting
- 服务器渲染 HTML,而不是 JSON——HTMX 请求返回 HTML 片段,而不是数据
- 使用局部模板进行动态更新——为 HTMX 响应拆分 文件
_partial.html - 渐进式增强——页面在没有 JavaScript 时也能工作,HTMX 则用于提升用户体验
- 尽量减少客户端复杂度——让服务器承担主要工作
Critical Hints & Reminders
关键提示与提醒
UX Best Practices
UX 最佳实践
Always include loading indicators
- Use to show loading states during requests
hx-indicator - Users should never wonder if their action worked
- Example:
<button hx-get="/data/" hx-indicator="#spinner">Load</button>
Always provide user feedback
- Use Django messages framework for success/error feedback
- Return error messages in HTMX responses, not silent failures
- Show what happened after an action completes
Handle errors gracefully
- Return proper HTTP status codes (400 for validation errors, 500 for server errors)
- Render form errors in partial templates
- Don't swallow exceptions - log and show user-friendly messages
始终包含加载指示器
- 使用 在请求期间显示加载状态
hx-indicator - 用户不应怀疑自己的操作是否生效
- 示例:
<button hx-get="/data/" hx-indicator="#spinner">Load</button>
始终提供用户反馈
- 使用 Django messages framework 提供成功或错误反馈
- 在 HTMX 响应中返回错误消息,不要静默失败
- 操作完成后展示执行结果
妥善处理错误
- 返回正确的 HTTP 状态码(验证错误使用 400,服务器错误使用 500)
- 在局部模板中渲染表单错误
- 不要吞掉异常——记录日志并显示对用户友好的消息
Django-Specific Patterns
Django 专属模式
Always detect HTMX requests
- Check to detect HTMX requests
request.headers.get("HX-Request") - Return partial templates for HTMX, full page templates otherwise
- Pattern:
if request.headers.get("HX-Request"): return render(request, "_partial.html", context)
Always return partials for HTMX
- HTMX requests should return templates, not full pages with
_partial.htmlbase.html - Full page responses to HTMX requests break the UX and send duplicate HTML
- Partials should be self-contained HTML fragments
Always validate request.method
- Check before processing form data
request.method == "POST" - Return proper status codes (405 Method Not Allowed for wrong methods)
CSRF is already configured globally
- The base template has on
hx-headers- no need to add CSRF tokens to individual forms<body> - All HTMX requests automatically include the CSRF token
始终检测 HTMX 请求
- 检查 以检测 HTMX 请求
request.headers.get("HX-Request") - 对 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>——无需在单个表单中添加 CSRF tokenhx-headers - 所有 HTMX 请求都会自动包含 CSRF token
Template Organization
模板组织
Naming convention
- Partials: (underscore prefix)
_partial.html - Full pages: (no prefix)
page.html - Example: (full page) includes
posts/list.html(partial)posts/_list.html
Structure
- Full page template extends and includes partial
base.html - Partial contains only the dynamic HTML fragment
- HTMX targets the partial's container div
Keep partials focused
- Each partial should represent one logical UI component
- Avoid partials that are too large or do too much
- Compose larger UIs from multiple smaller partials
命名约定
- 局部模板:(下划线前缀)
_partial.html - 完整页面:(无前缀)
page.html - 示例:(完整页面)包含
posts/list.html(局部模板)posts/_list.html
结构
- 完整页面模板继承 并包含局部模板
base.html - 局部模板只包含动态 HTML 片段
- HTMX 的目标指向局部模板的容器 div
让局部模板保持聚焦
- 每个局部模板应表示一个逻辑 UI 组件
- 避免局部模板过大或承担过多职责
- 由多个较小的局部模板组合出更大的 UI
Django View Patterns
Django 视图模式
HTMX Detection
HTMX 检测
Check the header to detect HTMX requests:
HX-Requestpython
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 请求:
HX-Requestpython
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)Form Handling Pattern
表单处理模式
Key points:
- Validate form normally
- On success: return partial with new data OR trigger client-side event
- On error: return partial with form errors
- Always handle both HTMX and non-HTMX cases
python
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 和非 HTMX 情况
python
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})Response Headers Reference
响应头参考
HTMX respects special response headers for client-side behavior:
HTMX 会遵循特殊响应头来控制客户端行为:
HX-Trigger
HX-Trigger
Trigger client-side events after response
- Use case: Update other parts of page after action
- Example:
response["HX-Trigger"] = "itemCreated" - Template listens:
<div hx-get="/count/" hx-trigger="itemCreated from:body">
在响应后触发客户端事件
- 使用场景:操作后更新页面的其他部分
- 示例:
response["HX-Trigger"] = "itemCreated" - 模板监听:
<div hx-get="/count/" hx-trigger="itemCreated from:body">
HX-Redirect
HX-Redirect
Client-side redirect
- Use case: Redirect after successful action
- Example:
response["HX-Redirect"] = reverse("app:detail", args=[obj.pk])
客户端重定向
- 使用场景:操作成功后进行重定向
- 示例:
response["HX-Redirect"] = reverse("app:detail", args=[obj.pk])
HX-Retarget / HX-Reswap
HX-Retarget / HX-Reswap
Override hx-target and hx-swap from server
- Use case: Different targets for success vs error
- Success:
response["HX-Retarget"] = "#main" - Error: Return partial without changing target (targets the form)
从服务端覆盖 和
hx-targethx-swap- 使用场景:为成功和错误情况使用不同目标
- 成功:
response["HX-Retarget"] = "#main" - 错误:返回局部模板但不更改目标(目标为表单)
HX-Refresh
HX-Refresh
Force full page refresh
- Use case: Major state change that affects whole page
- Example:
response["HX-Refresh"] = "true"
强制刷新完整页面
- 使用场景:发生影响整个页面的重大状态变化
- 示例:
response["HX-Refresh"] = "true"
Common Pitfalls
常见陷阱
- Missing loading indicators: Always use - users click multiple times without feedback
hx-indicator - Full pages in HTMX responses: Return , not full pages with
_partial.html- checkbase.htmlheaderHX-Request - Not handling form errors: Always return the form with errors on validation failure, not just the success case
- Not disabling buttons: Use to prevent duplicate submissions
hx-disabled-elt="this" - N+1 queries: HTMX views need /
select_related()just like regular viewsprefetch_related()
- 缺少加载指示器:始终使用 ——否则用户在没有反馈的情况下可能会重复点击
hx-indicator - 在 HTMX 响应中返回完整页面:应返回 ,而不是包含
_partial.html的完整页面——检查base.html请求头HX-Request - 未处理表单错误:验证失败时始终返回带有错误的表单,而不能只处理成功情况
- 未禁用按钮:使用 防止重复提交
hx-disabled-elt="this" - N+1 查询:与常规视图一样,HTMX 视图也需要使用 /
select_related()prefetch_related()
Integration with Other Skills
与其他 Skill 的集成
- django-templates: Partial template organization and inheritance patterns
- django-forms: HTMX form submission and validation
- django-extensions: Use to verify HTMX endpoints
show_urls - pytest-django-patterns: Testing HTMX endpoints and headers
- systematic-debugging: Debug HTMX request/response issues
- django-templates:局部模板组织与继承模式
- django-forms:HTMX 表单提交与验证
- django-extensions:使用 验证 HTMX 端点
show_urls - pytest-django-patterns:测试 HTMX 端点和请求头
- systematic-debugging:调试 HTMX 请求与响应问题