Django REST+VueJS与Django+HTMX组合比较

本文详细介绍了使用 Vue 和 Django REST Framework (DRF) 与 HTMX 和 Django 开发应用程序之间的差异。我们将研究一个简单的例子来说明这两种组合是如何工作的,并比较它们的优点和缺点。

Vue 和 Django REST 框架
根据StackOverflow 开发者调查, Vue虽然不如 Angular 和 React 受欢迎,但因其简单性和专注于 Web 应用程序的视图层而脱颖而出。它是轻量级的,只需一个JS 文件即可启动。与 React 或 Angular 相比,这使得学习曲线更加平缓,并且能够更顺利地集成到现有项目中。

虽然 Vue 本身非常强大,但附加的库和工具大大增强了 Vue 的功能。用于项目管理的Vite、用于状态管理的Pinia以及用于客户端路由的Vue Router等工具都有助于提供更强大的 Vue 开发体验。

Vue 的突出功能之一是单文件组件。此方法将 HTML 模板、JavaScript 逻辑和作用域 CSS 封装在单个文件中,以实现更好的组织和可维护性。这种结构不仅使 Vue 组件独立且易于理解,而且还演示了 Vue 反应式数据绑定的核心原理,这对于交互式 Web 应用程序至关重要。

由于 Vue 在浏览器中工作,因此它只能暂时保存数据。为了保存除此之外的数据,Vue 需要与后端服务器配对。由于 Vue 的性质,Vue 向后端服务器发送请求,然后处理响应,因此后端使用的框架影响很小。虽然本文使用Django REST Framework(当然还有 Django),但您可以轻松使用 FastAPI 或其他语言的框架。

让我们看一个生成密码的简单页面的示例。

DRF 提供了一个端点,当对特定 URL 提出 GET 请求时,它会返回一个包含password的响应:

# view
class GeneratePassword(APIView):
    def get(self, request):
        password = "".join(
            secrets.choice(string.ascii_letters + string.digits + string.punctuation)
            for _ in range(12)
        )
        return Response(password)


# URL
urlpatterns = [
    path(
"generate-password/", views.GeneratePassword.as_view(), name="generate_password"),
]

Vue 是一个独立的应用程序,它向密码端点发送请求并处理响应。Vue 应用程序的设置更为复杂,与密码端点直接交互的部分是密码组件:

<template>
  <p>{{password}}</p>
  <br>
  <button @click="getPassword">Generate a password</button>
</template>

<script>
import axios from 'axios';

export default {
  data() {
    return {
      password: ''
    };
  },
  methods: {
    getPassword() {
      const path = 'http:
//localhost:8000/generate-password/';
      axios.get(path)
        .then((res) => {
          this.password = res.data;
        })
        .catch((error) => {
          console.error(error);
        });
    }
  }
}
</script>

<style scoped>

</style>

该组件自给自足,可将 HTML、JS 和 CSS 放入同一个文件中。加载页面时,将显示密码的初始值(空)。当用户点击按钮时,会调用 getPassword 方法。在 Axios 库的帮助下,该方法会唤起对 API 端点的调用。得到的数据会保存在名为 message 的数据属性中。由于双向绑定数据已更改,页面中显示该数据的部分也会随之更新。

HTMX 和 Django
HTMX 有 "讨厌 JavaScript 的人的 JavaScript 框架 "之称。由于其轻量级和易用性,它正在迅速流行起来。如果您以前使用过任何前端框架,都会对它有一种完全不同的感觉--与其说它是一个框架,不如说它是打了类固醇的 HTML。使用 HTMX 时,只需在 HTML 中直接使用少量 HTMX 特有的属性,就能轻松实现动态页面渲染。

这些核心属性允许你为请求设置 HTTP 方法和 URL(如 hx-put),设置什么事件会触发它(hx-trigger),以及设置响应会改变的元素(hx-target)。

使用 HTMX 和 Django 的最简单方法就是将它们紧密结合在一起。与 Vue 和 DRF 的配对不同,Vue 和 DRF 的每个框架都可以独立更换,而 Django 或 HTMX 则不能拔下插头就换成其他东西(至少不容易)。

一方面,用于 HTMX 交互的 Django 代码与普通 Django 代码不同。相反,HTMX 被直接嵌入 Django 模板中,而不是作为单独的文件存在。一旦决定使用这种组合,用其他工具替换其中任何一种都需要彻底重写。

另一方面,使用纯 Django 并决定在使用过程中需要更多的交互性,对于轻量级 HTMX 来说也不成问题。您的整个项目可以完全依赖 Django,几个月后添加一个 HTMX 功能几乎不需要任何开销。

让我们看看用 Django 和 HTMX 完成同样的事情--一个简单的密码生成器--会是什么样子。

HTMX 被简单地包含在 Django 中,这意味着没有特定的 HTMX 文件。视图和 URL 与普通 Django 中的一模一样:

# views
class GeneratePasswordPage(TemplateView):
    template_name = "generate_password_page.html"


class GeneratePassword(APIView):
    def get(self, request):
        password =
"".join(
            secrets.choice(string.ascii_letters + string.digits + string.punctuation)
            for _ in range(12)
        )
        return Response(password)


# URLs
urlpatterns = [
    path(
"password/", views.GeneratePasswordPage.as_view(), name="generate_password_page"),
    path(
"password/generate", views.GeneratePasswordPartial.as_view(), name="generate_password_partial")
]

该模板是典型的 Django 模板,其中加入了一些 HTMX:

{% extends 'base.html' %}

{% block content %}
  <p id="password">{{ password }}</p>
  <br>
  <button hx-get=
"{% url 'generate_password_partial' %}"
          hx-target=
"password"
  >
    Generate a password
  </button>
{% endblock %}

如您所见,该模板比 Vue 对应模板更简单。它几乎完全依赖于 Django -- HTMX 发送请求并将响应包含在 HTML 中。

HTMX 没有内置的状态管理;它完全依赖于后端(在我们的例子中是 Django)来管理状态。在本例中,Django 提供了两个端点,因为与 Vue 管理初始页面的情况不同,这里是 Django 负责提供初始页面。点击按钮后,会向第二个端点发出请求。该端点会返回一个包含密码的响应。HTMX 会将该密码包含在页面中。

与纯 Django 相比,将其与 HTMX 结合需要大量零散的 Django 视图。使用 HTMX 来实现类似于 Vue 的应用程序,其中有许多可更改的组件,这很快就会变得难以管理。

在这两种情况下,我们创建的应用程序都能在点击按钮后生成密码,而无需重新加载整个页面。但我们达到这一目的的方式却截然不同。

HTMX 与 Vue
必须明白,直接比较 HTMX 和 Vue 就像比较苹果和橘子一样。它们解决的是Web开发中完全不同的方面。

HTMX 专注于服务器驱动的交互,将数据传递给服务器,并根据服务器的响应更新页面。Vue 的主要目的是在客户端构建和管理动态用户界面。这一主要区别波及开发过程的方方面面。

HTMX 和 Vue 之间最显著的区别之一是它们如何管理状态

  • HTMX 是无状态的,依赖服务器端进行状态管理,
  • 而 Vue 则直接在浏览器中处理状态,这对于创建更动态的用户体验至关重要。

HTMX 无疑没有那么复杂--它只是 HTML 的增强版,而 Vue 则是一个成熟的前端框架。虽然在现有项目中添加 Vue 比 React 更简单,但仍比添加 HTMX 复杂。不过,Vue 的设计使复杂性保持在可控范围内,即使您扩大项目规模也是如此。HTMX 虽然对于小规模添加来说简单明了,但对于规模更大、更复杂的实现来说,就会变得更加棘手。

无论您选择哪种方案,它都不可能是您需要的唯一工具。

  • Vue 拥有丰富的生态系统,可与 CSS 框架、路由、状态管理等集成。甚至还有一个浏览器开发工具来帮助开发。
  • HTMX 提供了少量扩展,并可与其他第三方工具互补,但缺乏官方集成选项。虽然 HTMX 通常与 Alpine.js 和 Tailwind CSS 等工具搭配使用,但这些工具仍然是独立的,没有专门的集成工具将它们无缝连接起来。

测试和部署
在决定使用哪个框架时,测试和部署这两个方面经常被忽视。

拥有两个独立的项目需要两个开发环境和不同的测试方法。

  • Vue 可以隔离测试,您需要模拟后台响应;也可以使用后台的实际响应进行测试,在这种情况下,您需要一个专用的测试环境。使用真实 API 进行的测试往往更慢、更不稳定,但更接近现实。
  • HTMX 添加到 Django 后,主要可以使用 Django 的测试工具进行测试,对于最关键的用户流,还可以使用 Cypress 等工具进行补充。

关于部署,在使用 DRF/Vue 时,最常见的方案是:

  • 将它们分开部署--例如,两个 Docker 容器。
  • 然后,您需要从不同的域为它们提供服务,并设置 CORS 标头,
  • 或者将它们部署在基于路径的代理后面--例如,将所有以 /api/ 前缀开始的请求路由到 DRF 容器;其余的请求路由到同一域上的 Vue。

在这种情况下,您还需要处理两端已通过身份验证/未通过身份验证的用户可以访问/显示的内容--例如,阻止未通过身份验证用户的 API 请求,当 API 拒绝未通过身份验证的请求时,重定向到 Vue 内部的登录页面。

虽然这听起来像是很大的开销,但在需要构建客户端丰富的应用程序或拥有不同客户端的情况下,这就非常合理了。例如,如果您需要为 iOS 应用程序构建一个 API,那么您不妨在 Web Vue 应用程序中重复使用它。

Vue 与 Django REST 框架 vs. HTMX 与 Django
用前者和后者替代这两种组合:

学习曲线:

  • 前者:更陡峭的学习曲线。
  • 后者:较低的学习曲线。

开发方式:

  • 前者:SPA(单页应用程序)。需要单独的 REST API。
  • 后者:多页面应用程序方法。通过 AJAX 功能增强 Django 模板。

互动性:

  • 前者:高水平的互动性。非常适合具有实时数据更新的动态和复杂的用户界面。
  • 后者:互动性适中。非常适合向页面添加动态行为,而无需 JavaScript 框架的复杂性。

搜索引擎优化:

  • 前者:需要额外考虑 SEO,因为 SPA 本质上并不适合 SEO。
  • 后者:由于内容是服务器渲染的,因此开箱即用的搜索引擎优化效果更好。

扩展性:

  • 前者:更适合需要丰富的客户端体验或支持多个客户端的大型复杂应用程序。
  • 后者:更适合不需要全面 SPA 复杂性的中小型应用程序。

结论
本文深入探讨了使用 Vue 和 Django REST Framework (DRF) 与 HTMX 和 Django 开发应用程序之间的差异。

根据您的需求和偏好,您现在可以就使用哪种组合做出更明智的决定。

在使用 Django REST Framework 的 Vue 和使用 Django 的 HTMX 之间进行选择取决于您项目的具体要求和目标以及开发团队的专业知识。