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

Django基于版本的乐观锁更新问题:如何避免并发编辑冲突?

解决方案:实现Django并发编辑的版本冲突检测

1. 修改表单,添加隐藏版本字段

由于模型中version字段设置了editable=False,默认不会被表单渲染,因此需要手动在表单中添加隐藏字段,用来传递用户打开页面时的版本号,确保提交时能拿到旧版本信息做校验。

修改你的MyModelForm:

from django import forms
from .models import MyModel

class MyModelForm(forms.ModelForm):
    # 添加隐藏字段存储版本号
    version = forms.IntegerField(widget=forms.HiddenInput())

    class Meta:
        model = MyModel
        fields = ['name', 'version']  # 显式包含version字段

2. 修正视图逻辑,确保原子性版本校验

现有视图存在缩进错误,导致版本校验逻辑未被正确执行;同时为避免并发场景下的竞态问题(如查询和保存之间有其他请求修改数据),建议使用数据库层面的条件更新,保证操作原子性。

修改后的视图代码:

from django.shortcuts import get_object_or_404, render, redirect
from .models import MyModel
from .forms import MyModelForm

def updateModel(request, id): 
    toUpdate = get_object_or_404(MyModel, pk=id)    
    if request.method == 'POST':
        form = MyModelForm(request.POST, instance=toUpdate)
        if form.is_valid():
            # 获取提交上来的旧版本号
            submitted_version = form.cleaned_data['version']
            # 原子更新:仅当数据库版本与提交版本匹配时,才更新数据并递增版本
            updated_count = MyModel.objects.filter(pk=id, version=submitted_version).update(
                name=form.cleaned_data['name'],
                version=submitted_version + 1
            )
            if updated_count == 1:
                # 更新成功,版本匹配
                return redirect('somewhere')
            else:
                # 更新失败,触发版本冲突提示
                form.add_error(None, '该数据已被其他用户修改,请刷新页面后重新编辑。')
    # GET请求时生成表单,自动携带当前版本号
    form = MyModelForm(instance=toUpdate)
    return render(request, 'somwhere2/createupdate.html', {'form': form})

3. 前端模板处理

模板中正常渲染表单即可,隐藏的version字段会自动被渲染,同时添加错误提示区域:

<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">保存</button>
    {% if form.non_field_errors %}
        <div class="error-message">
            {{ form.non_field_errors }}
        </div>
    {% endif %}
</form>

核心逻辑说明

  • 隐藏字段确保提交时携带的是用户打开页面时的版本号,而非当前数据库的最新版本,以此识别并发编辑冲突。
  • 使用filter(...).update()实现原子操作,避免查询和更新之间的中间状态竞态,数据库层面直接执行条件判断与更新,可靠性更高。
  • 当updated_count为0时,说明无匹配版本的记录被更新,即数据已被其他用户修改,此时返回冲突提示。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 19:50:29