Django 支持 Triptych:让按钮、HTTP 方法与局部更新回归原生 HTML

2026-07-15 25 预计阅读时间: 1 分钟
来源: djangoproject.com AI 摘要 Original link

Disclaimer: This article is an AI-assisted summary. Read it together with the original source when precision matters. The summary may omit context, version differences, or edge cases and is not official documentation.

预计阅读时间:10 分钟

Django Steering Council 以 Django Software Foundation 技术治理机构的身份,为 Triptych Project 的资金申请提供了合作支持。这个项目试图把 HTMX、Unpoly、Turbo 等库验证过的部分模式带入 HTML 标准,让浏览器原生支持更完整的 HTTP 方法、独立按钮操作和局部页面替换。

这项工作与 Django 的方向高度契合:服务器渲染模板,传输 HTML,让浏览器负责导航、表单和页面更新。Django 6.0 加入模板局部片段,也说明“HTML over the wire”已经开始影响框架本身。

Triptych 想补齐 HTML 的三块能力

Triptych 包含三项相对聚焦的提案:

  • 允许表单使用 PUTPATCHDELETE,补全 HTML 对常用 HTTP 方法的表达能力。
  • 允许 <button> 自己声明请求地址和方法,不再强制依附于外层 <form>。这是目前重点推进的部分。
  • 允许链接、表单和按钮指定要替换的 DOM 区域,实现浏览器原生的局部页面更新。

它们解决的是同一个问题:许多常见交互在语义上并不复杂,但今天要么需要额外 JavaScript,要么需要用不够准确的 HTML 结构绕过去。

以退出登录为例,当前兼容所有浏览器的写法通常是:

<form action="/logout/" method="post">
  <input type="hidden" name="csrfmiddlewaretoken" value="{{ csrf_token }}">
  <button type="submit">退出登录</button>
</form>

按钮操作提案希望允许开发者直接表达:

<button action="/logout/" method="post">退出登录</button>

后一种结构更接近真实意图:用户触发的是一个操作,而不是填写并提交一张表单。不过,这仍是标准提案,不能当作当前浏览器已经普遍实现的功能。生产项目必须保留兼容写法,并继续处理 Django 的 CSRF 防护。

Django Admin 暴露出的语义问题

Django Admin 的对象编辑页通常提供“保存”“保存并新增”“保存并继续编辑”等多个提交入口。当前实现可以让这些控件共享外层表单的提交地址,再根据被提交按钮的 name 判断用户意图。

这种方案稳定有效,但它把多个动作塞进了同一个端点。视图需要检查 _save_addanother_continue 等字段,然后决定跳转到哪里。删除入口则常被写成外观类似按钮的链接,先导航到确认页面,再通过表单执行删除。

这里真正需要区分的是链接和按钮:

  • 链接表示导航到一个资源。
  • 按钮表示执行一个动作,动作可能成功、失败,也可能要求确认。

把删除操作写成链接并不意味着 Django 的行为错误;确认页仍然是正确的安全设计。问题在于 HTML 标记没有准确表达“这是删除流程的起点”。如果按钮能独立声明动作地址,请求意图就能直接留在标记中,服务器端也更容易把不同动作映射到不同视图。

现在就能采用的 Django 多动作写法

在按钮操作提案进入浏览器之前,可以这样实践:继续使用标准 <form>,利用现有的 formaction 属性为不同提交按钮选择不同端点。下面的最小示例适用于现有浏览器,也保留 Django 的 CSRF 校验。

先定义 URL。把示例中的 notes 替换成实际应用名:

# notes/urls.py
from django.urls import path

from . import views

urlpatterns = [
    path("notes/<int:pk>/edit/", views.edit_note, name="edit_note"),
    path("notes/<int:pk>/save/", views.save_note, name="save_note"),
    path("notes/<int:pk>/publish/", views.publish_note, name="publish_note"),
]

然后把保存和发布拆成明确的 POST 端点:

# notes/views.py
from django.http import HttpResponse
from django.shortcuts import get_object_or_404, redirect, render
from django.views.decorators.http import require_POST

from .models import Note


def edit_note(request, pk):
    note = get_object_or_404(Note, pk=pk)
    return render(request, "notes/edit.html", {"note": note})


@require_POST
def save_note(request, pk):
    note = get_object_or_404(Note, pk=pk)
    note.title = request.POST.get("title", "").strip()
    note.save(update_fields=["title"])
    return redirect("edit_note", pk=note.pk)


@require_POST
def publish_note(request, pk):
    note = get_object_or_404(Note, pk=pk)
    note.title = request.POST.get("title", "").strip()
    note.is_published = True
    note.save(update_fields=["title", "is_published"])
    return HttpResponse("已发布", status=200)

模板中的两个按钮提交同一批字段,但进入不同视图:

<!-- templates/notes/edit.html -->
<form method="post" action="{% url 'save_note' note.pk %}">
  {% csrf_token %}

  <label for="title">标题</label>
  <input id="title" name="title" value="{{ note.title }}" required>

  <button type="submit">保存草稿</button>
  <button
    type="submit"
    formaction="{% url 'publish_note' note.pk %}"
    formmethod="post"
  >发布</button>
</form>

运行前需要保证 Note 模型至少包含 titleis_published 字段,并把应用 URL 接入项目根路由。这个例子不是 Triptych 新 API,而是今天可以使用的过渡方案:动作已经拆成不同服务器端端点,只是按钮暂时仍需放在表单里。

标准能力落地后仍需处理的边界

原生 HTML 能减少客户端依赖,但不会自动解决应用层问题。

CSRF 仍然存在。 浏览器即使支持按钮直接发送 POST、PUT 或 DELETE,Django 应用仍需要提交 CSRF token,或者由未来标准和框架集成提供明确的传递方式。在这一点没有确定方案之前,不能为了更短的标记关闭 CSRF 校验。

危险操作仍应确认。 删除、撤销付款或吊销密钥不应该因为按钮能直接发送 DELETE 就省略确认步骤。HTTP 方法表达语义,确认页面控制风险,两者不是替代关系。

局部替换需要定义失败行为。 如果服务器返回验证错误、登录页面或 500 响应,浏览器应该替换哪个区域、如何更新历史记录、焦点移到哪里,都关系到可访问性和可恢复性。这也是标准化比实现一个 JavaScript 库更慢的原因之一。

框架需要适配新请求。 Django 目前最成熟的表单处理路径围绕 GET 和 POST 展开。未来即使浏览器原生发送 PUT、PATCH 和 DELETE,框架、表单绑定、中间件以及测试工具也需要形成一致的解析和安全策略。

如何评估和参与

团队采用这类能力时,可以按以下清单推进:

  • 当前页面优先使用语义正确的链接、按钮和表单,不把视觉样式当作元素语义。
  • 多动作页面先用 formaction 和独立 Django 视图拆分职责。
  • 对新提案采用渐进增强,在主流浏览器实现之前保留标准表单回退路径。
  • 持续测试 CSRF、键盘操作、焦点管理、浏览器历史记录和错误响应。
  • 阅读标准提案,并基于真实 Django 项目中的案例提供建设性反馈。
  • 使用 Django 或 HTML-over-the-wire 技术的公司,可以通过正式但不具约束力的支持信帮助项目申请持续投入标准工作的资金。

Triptych 的价值不只是少写几行 JavaScript。它试图让浏览器重新拥有应用开发中最常见的一批能力,使 Django 这类服务器端框架可以用更准确的 HTML 表达动作、请求和局部更新。标准落地会很慢,但一旦进入浏览器,它带来的能力不属于某个框架或依赖包,而会成为整个 Web 平台的长期基础设施。


相关推荐