游乐游手机版
首页/前端开发/文章详情

如何用拖放在Flask看板应用中更新数据库状态

时间:2026-07-09 07:01
在Flask看板应用中,通过HTML5拖放API结合前端fetch异步POST请求,将拖拽任务的task_id和target_state发送至后端路由;后端接收JSON后更新数据库并提交事务,实现跨列拖拽时实时更新状态。需注意将事件绑定到容器而非子元素,并在ondragover中阻止默认行为以确保drop触发。
本文深入解析在 Flask + Jinja2 构建的看板系统中,如何巧妙运用 HTML5 Drag and Drop API 与后端逻辑联动,实现任务卡片跨列(to-do / in progress / done)拖拽时即时更新数据库状态。同时重点剖析事件未触发、子元素干扰、服务端函数误执行等典型陷阱及对应解决方案。

在 Flask + Jinja2 搭建的看板应用中,如果你尝试让任务卡片跨列拖拽后自动更新数据库,大概率会踩进同一个坑:以为在 drop 事件里直接调用 {{ dropped(...) }} 就行。但事实是,Jinja2 模板中的这组花括号语法,在页面渲染到浏览器之前就已经被服务端计算完毕——它并非 JavaScript 函数,不会等你拖拽结束再执行。所以很多人的实现就直接“趴窝”了。

那该怎么办?我们先厘清一个非常常见的误区:

✅ 正确思路不是让模板去调后端,而是通过前端 fetch() 向 Flask 路由发送一条异步 POST 请求,把拖拽的 task_idtarget_state 打包成 JSON 发给后端;后端收到后更新数据库、提交事务,然后返回一个重定向响应。

✅ 前端实现:给容器绑定事件,而非子元素

在结构上,ondropondragover 这类事件必须绑定在

    容器(即 drop zone)上,并通过 this 把当前容器传入函数。这样做主要是为了避免事件被
  1. 或其中的

    {{ pending.description }}

  2. {% endfor %}

对应的 JavaScript 部分,需要用一个计数器来防止子元素进入/离开时反复触发样式变化,同时用 fetch 把拖放数据送到后端:

⚠️ 千万别忽略 ondragover 里的 ev.preventDefault(),这是 drop 事件能够触发的先决条件。另外,在 dragEnter/dragLea ve 中添加 ev.stopPropagation() 可以避免子元素打断计数逻辑。

✅ 后端实现:用单一路由同时处理 GET 和 POST

Flask 端的实现并不复杂,关键在于区分普通表单提交和 JSON 拖放请求。前者走 request.form,后者走 request.json。更新完任务状态后在 session 中提交,然后重定向回当前看板——以下代码最为清晰:

@main.route("//kanban", methods=["GET", "POST"])def kanban(project_id):    project = Project.query.get(project_id)    if not project:        return render_template("404.html"), 404    try:        session = sessions_by_project[project_id]    except KeyError:        return render_template("404.html"), 404    tasks_by_status = defaultdict(list)    for depth, task in walk_list(session.query(Task).all()):        tasks_by_status[task.status.value].append((depth, task))    # 普通表单提交(例如点击任务按钮)    if request.method == "POST" and "task" in request.form:        return redirect(url_for("main.task", project_id=project_id, id=int(request.form["task"])))    # 拖放 JSON 更新    if request.method == "POST" and request.is_json:        data = request.get_json()        if "task_id" in data and "target_state" in data:            task_id = int(data["task_id"])            target_state = data["target_state"]            task = session.query(Task).get(task_id)            if not task:                return render_template("404.html"), 404            task.change_status(str2status(target_state))            session.commit()            return "", 204    return render_template("kanban.html", tasks_by_status=tasks_by_status, project=project)

来源:https://www.php.cn/faq/2746453.html
上一篇如何用CSS :has()选择器快速实现悬停span显示相邻div
本站内容用于信息整理与展示,如有侵权或内容问题请及时联系处理。

相关推荐

补充同频道和同主题内容,方便继续浏览更多相关内容。

同类最新

继续查看同栏目最近更新的文章。

更多