使用纯Python构建Web应用

2023-10-31 08:19:58 浏览数 (1)

最近在研究htmx库的时候突发奇想,利用 htmx 和我之前发布的 Python 库html-dsl应该可以做到只使用 Python 代码构建可交互的 Web 应用。在稍作尝试后,我实现了一个简单的 Todo 应用todopy。

技术栈

FastAPI

项目后端使用了FastAPI框架。

html-dsl

html-dsl 是我在数年前开发的一个简单的 Python 库,可以利用 Python 代码构建 HTML 页面,使用比较简单。

htmx

(由 Github Copilot 生成) htmx 是一个 JavaScript 库,它允许您使用 HTML 扩展现有的 Web 应用程序,而无需编写任何 JavaScript。它使用现有的 Web 标准(例如 HTML、CSS 和 JavaScript)来实现 Ajax、WebSockets、Server-Sent Events 和其他现代 Web 功能。htmx 的目标是使 Web 开发更快、更简单、更容易,并提高 Web 应用程序的可访问性。

代码语言:javascript复制
<script src="https://unpkg.com/htmx.org@1.9.6"></script>
<!-- have a button POST a click via AJAX -->
<button hx-post="/clicked" hx-swap="outerHTML">Click Me</button>

在上面的示例中,点击按钮后,htmx 将向服务器发送一个 POST 请求,该请求将被路由到/clicked。服务器将返回一个 HTML 片段,该片段将替换按钮的外部 HTML。

tailwindcss

tailwindcss是一个实用的 CSS 库,它提供了一组实用的 CSS 类,可以快速构建页面。

构建页面

整个页面比较简单,核心是一个输入新待办项的表单和一个待办项列表。

整体布局

代码语言:javascript复制
@app.get("/")
def root():
    return render(
        HTML(lang="en")[
            HEAD[
                META['charset="utf-8"'],
                META['name="viewport" content="width=device-width, initial-scale=1"'],
                TITLE["Todo App"],
                SCRIPT(src="https://unpkg.com/htmx.org@1.9.6"),
                SCRIPT(src="https://cdn.tailwindcss.com"),
                STYLE[GLOBAL_STYLE],
            ],
            BODY[
                DIV(_class="max-w-md max-auto")[
                    H1(_class="text-2xl font-bold mb-4")["Todo List"],
                    FORM(_class="mb-4", hx_post="/todos", hx_target="#todo-list")[
                        DIV(_class="flex items-center")[
                            INPUT(
                                type="text",
                                name="task",
                                _class="border rounded-l px-3 py-2 w-full",
                                placeholder="Add new todo",
                            ),
                            BUTTON(
                                type="submit",
                                _class="bg-blue-500 hover:bg-blue-700 text-white font-bold rounded-r px-4 py-2",
                            )["Add"],
                        ]
                    ],
                    DIV(id="todo-list", hx_get="/todos", hx_trigger="load"),
                ],
            ],
        ]
    )

待办项列表由 id 为 todo-list 的 div 元素渲染,当页面加载完成后,htmx 会向服务器发送一个 GET 请求,服务器返回一个待办项列表的 HTML 片段,然后将其插入到 todo-list 元素中。

表单的提交也由 htmx 处理,当用户点击提交按钮时,htmx 会向服务器发送一个 POST 请求,服务器将新的待办项添加到数据库中,然后返回一个待办项列表的 HTML 片段,htmx 将其插入到 todo-list 元素中。

渲染待办项列表

代码语言:javascript复制
def render_todos(todos):
    return render(
        UL(_class="border rounded-lg overflow-hidden")[
            [
                LI(_class="flex items-center justify-between px-3 py-2 border-b")[
                    SPAN(_class="text-lg")[todo],
                    BUTTON(
                        hx_delete=f"/todo/{id}",
                        hx_target="#todo-list",
                        _class="text-red-500 hover:text-red-700",
                    )["delete"],
                ]
                for id, todo in todos.items()
            ]
        ]
    )

页面加载、添加新待办项,以及待办项列表中的删除按钮都会触发重新渲染待办项列表,于是我封装了一个 render_todos 函数,用于渲染待办项列表的 HTML 片段。其中每一个待办项都是一个 li 元素,包含一个 span 元素和一个删除按钮。删除按钮的点击事件由 htmx 处理,当用户点击删除按钮时,htmx 会向服务器发送一个 DELETE 请求,服务器将待办项从数据库中删除,然后返回一个待办项列表的 HTML 片段,htmx 将其插入到 todo-list 元素中。

后端接口

整体比较简单,只有三个接口,分别用于获取待办项列表、添加新待办项和删除待办项。 与常规的 restful 接口不同的是,这里的接口都返回 HTML 片段,而不是 JSON 数据。

代码语言:javascript复制
@app.get("/todos")
def todos_list(todos: Annotated[dict, Depends(todos)]):
    return render_todos(todos)


@app.post("/todos")
def todos_add(todos: Annotated[dict, Depends(todos)], task: str = Form("task")):
    id = uuid.uuid4().hex
    todos[id] = task
    return render_todos(todos)


@app.delete("/todo/{id}")
def todos_delete(todos: Annotated[dict, Depends(todos)], id: str):
    del todos[id]
    return render_todos(todos)

总结

这个 todo 应用只是一个玩具项目,不过 htmx 还是很强大的,即使不使用 html-dsl 这种纯 Python 的 HTML 构建库,也可以利用常规的 HTML 模板引擎(例如 Jinjia2)来构建页面,赋予了纯后端开发人员构建可交互 Web 应用的能力。

0 人点赞