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
相关产品推荐
相关产品推荐

