You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django实现动态编辑锁:用户活跃编辑时锁定实例阻止他人打开

Django编辑页动态锁实现方案

基础技术栈

  • 后端:Django框架
  • 前端:原生HTML/CSS/JavaScript,未引入React等交互式UI库

原有锁定逻辑

以实例X的编辑表单页为例,当前采用静态锁定规则:

  • 用户打开编辑页面时,系统直接在数据库写入锁定标识,标记该实例已被当前编辑者锁定
  • 仅当用户主动点击「保存」或「关闭」按钮完成操作后,系统才会解除锁定,开放给其他用户使用

现存问题

如果编辑者未保存内容、也未点击「关闭」按钮就直接离开页面,对应实例会一直保持锁定状态,必须等该用户返回手动解锁才能释放,其他用户无法正常编辑,严重影响协作效率。

目标动态锁定规则

核心逻辑为仅当用户处于活跃编辑状态时,才持有实例的编辑锁,其中「活跃」判定标准:

  • 用户当前停留在编辑页面,且对应标签页在浏览器中处于激活状态
  • 触发以下任意场景时,系统自动释放编辑锁,开放给其他用户:
    • 用户直接关闭标签页/整个浏览器
    • 标签页失活(切换到其他标签、最小化浏览器等)时长累计达到5分钟

具体实现

后端(Django侧)

  1. 改造原有锁数据表,在原有「关联实例ID」「锁定用户ID」字段基础上,新增3个字段:
    • last_heartbeat:DateTime类型,记录最近一次收到用户活跃心跳的时间
    • lock_session_key:Char类型,记录持有锁的用户会话标识,避免同个用户多开标签页导致锁冲突
    • is_valid:Boolean类型,标记锁是否处于有效状态
  2. 编写3个接口供前端调用:
    • acquire_lock 加锁接口:用户首次进入编辑页时调用,先校验当前实例是否存在有效锁(即is_valid=True、last_heartbeat与当前时间差小于5分钟、锁不属于当前会话),如果存在有效锁直接返回「实例正在被其他用户编辑」的错误提示;如果不存在有效锁,则写入/更新锁记录,绑定当前会话,将last_heartbeat设为当前时间,返回加锁成功标识
    • renew_lock 心跳续约接口:前端定时调用,校验锁归属当前会话后,将last_heartbeat更新为当前时间即可
    • release_lock 主动解锁接口:用户点击保存/关闭按钮、页面正常关闭时调用,将对应锁记录的is_valid设为False
  3. 锁过期逻辑无需单独配置定时任务,每次收到加锁请求时,顺手将所有last_heartbeat与当前时间差超过5分钟的锁标记为is_valid=False即可,足够支撑中小流量场景,减少运维成本。

前端(原生JS侧)

  1. 页面首次加载完成后,先调用acquire_lock接口,加锁成功才渲染可编辑表单,加锁失败直接展示提示信息,禁止编辑。
  2. 监听visibilitychange事件感知标签页激活状态:
    • 当document.visibilityState === 'hidden'时,记录失活起始时间戳,暂停心跳续约请求
    • 当document.visibilityState === 'visible'时,计算累计失活时长,如果时长超过5分钟直接禁用表单,提示「编辑锁已过期,请刷新页面重新申请编辑权限」;如果时长未超过阈值,先调用一次renew_lock接口续约,再恢复心跳定时器
  3. 心跳续约逻辑:标签页处于激活状态时,每1分钟调用一次renew_lock接口即可,无需过高频率减少服务端压力;如果接口返回锁已失效,直接禁用表单展示过期提示。
  4. 监听beforeunload事件,用户关闭标签页、跳转其他页面时,通过navigator.sendBeacon调用release_lock接口主动解锁,该方法不会被浏览器页面卸载流程拦截,可靠性远高于普通AJAX请求。

踩坑提示:不要在unload事件中绑定普通AJAX请求发送解锁信号,大多数浏览器会直接拦截卸载阶段的异步请求,导致解锁失败。


内容的提问来源于stack exchange,提问作者Yasser Mohsen

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 23:30:38