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

关于Django互斥并发编辑功能的实现方式与位置的疑问

嘿,我来帮你把这个并发编辑互斥的实现思路捋清楚,顺便给你明确下各个部分的代码位置~

一、先把模型层的逻辑补扎实

你已经在Order模型里加了locked字段和lock_edit方法,这是个很好的起点,但要注意数据库原子性——不然多个用户同时抢锁的时候,很可能出现“都读到锁是未占用,然后都改成锁定状态”的竞争问题。

优化后的模型代码可以这么写:

from django.db import models
from django.db.models import F
from django.utils import timezone
from django.contrib.auth.models import User

class Order(models.Model):
    edit_version = models.IntegerField(default=0, editable=True) # 用于乐观锁校验
    locked = models.BooleanField(default=False)
    locked_by = models.ForeignKey(User, null=True, blank=True, on_delete=models.SET_NULL) # 记录锁的持有者
    locked_at = models.DateTimeField(null=True, blank=True) # 记录锁的创建时间,用于超时释放

    def lock_edit(self, user):
        # 用数据库原子更新操作,确保只有当锁未被占用时才会成功锁定
        updated_rows = Order.objects.filter(id=self.id, locked=False).update(
            locked=True,
            locked_by=user,
            locked_at=timezone.now()
        )
        # 更新成功就刷新当前实例的字段,返回True;失败返回False
        if updated_rows > 0:
            self.refresh_from_db()
            return True
        return False
    
    def unlock_edit(self):
        # 同样用原子操作解锁
        updated_rows = Order.objects.filter(id=self.id).update(
            locked=False,
            locked_by=None,
            locked_at=None
        )
        if updated_rows > 0:
            self.refresh_from_db()
            return True
        return False
二、视图层是核心逻辑触发点

互斥控制的主要逻辑都要放在视图里,分两个关键时机处理:

1. 用户进入编辑页面时抢锁

当用户点击“编辑”按钮进入表单页,就要立刻尝试获取锁,避免多个用户同时进入编辑状态:

from django.shortcuts import get_object_or_404, redirect
from django.contrib import messages
from .models import Order
from .forms import OrderForm

def order_edit(request, pk):
    order = get_object_or_404(Order, pk=pk)

    # 处理GET请求:用户进入编辑页,尝试抢锁
    if request.method == 'GET':
        # 先检查锁是否存在,并且是否超时(比如超过15分钟自动释放)
        if order.locked:
            if timezone.now() - order.locked_at > timezone.timedelta(minutes=15):
                order.unlock_edit()
            else:
                messages.error(request, f"该订单正在被{order.locked_by.username}编辑,请稍后再试")
                return redirect('order_detail', pk=pk)
        
        # 尝试获取锁,失败就提示用户
        if not order.lock_edit(request.user):
            messages.error(request, "获取编辑锁失败,请刷新页面重试")
            return redirect('order_detail', pk=pk)

    # 处理POST请求:提交表单
    form = OrderForm(request.POST or None, instance=order)
    if request.method == 'POST' and form.is_valid():
        # 二次校验:确保当前用户仍然持有锁,防止锁超时后被其他人修改
        if order.locked != True or order.locked_by != request.user:
            messages.error(request, "该订单已被其他用户修改或锁定,请刷新页面重新编辑")
            return redirect('order_edit', pk=pk)
        
        # 配合你原来的edit_version做乐观锁校验,防止提交过时数据
        if form.instance.edit_version != order.edit_version:
            messages.error(request, "该订单已被更新,请刷新页面后重新编辑")
            return redirect('order_edit', pk=pk)
        
        # 保存数据,更新版本号,然后解锁
        form.instance.edit_version += 1
        form.save()
        order.unlock_edit()
        messages.success(request, "订单编辑成功")
        return redirect('order_detail', pk=pk)

    return render(request, 'order_edit.html', {'form': form, 'order': order})

2. 表单提交时的双重校验

即使进入页面时拿到了锁,提交前也要再次确认锁的状态——比如用户打开页面后离开太久,锁超时自动释放,这时候另一个用户修改了订单,当前用户的提交就会是过时数据,必须拦截。

三、模板层给用户直观提示

在订单列表或详情页,给用户显示锁的状态,避免无效操作:

<!-- 订单详情页示例 -->
{% if order.locked %}
    <div class="alert alert-warning">
        🔒 该订单正在被{{ order.locked_by.username }}编辑,锁定时间:{{ order.locked_at|date:"Y-m-d H:i:s" }}
        {% if user == order.locked_by %}
            <a href="{% url 'order_edit' order.pk %}" class="btn btn-sm btn-primary ms-2">继续编辑</a>
        {% endif %}
    </div>
{% else %}
    <a href="{% url 'order_edit' order.pk %}" class="btn btn-sm btn-primary">编辑订单</a>
{% endif %}
四、额外优化建议
  • 自动解锁定时任务:用Celery之类的工具做定时任务,定期清理超过30分钟的无效锁,防止订单被永久锁定
  • 前端实时检查:在编辑页每隔1分钟发一次AJAX请求,检查锁是否仍有效,失效就及时提示用户
  • 权限控制:在抢锁前先校验用户是否有编辑该订单的权限,避免无权限用户占用锁

这样一套流程下来,就能完美实现“同一表单不能被多用户同时编辑”的互斥效果啦~

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 09:33:33