简体   繁体   English

Django 表单更新乐观锁定,基于版本

[英]Django form update optimistic locking, version based

I've got django model and view implemented like here: (+mysql db)我有 django model 和视图实现如下:(+ mysql db)


class MyModel(models.Model): 
    name = models.CharField(max_length=100)
    version = models.IntegerField(default=1, editable=False)

def updateModel(request, id): 
    toUpdate = MyModel.objects.get(pk=id)    
    if request.method=='POST':
        form = MyModelForm(request.POST,  instance=toUpdate)
        if form.is_valid(): 
        actual =  MyModel.objects.get(pk=id)    
        if (actual.version == form.instance.version):
            form.instance.version = form.instance.version+1
            form.save()
            return redirect('somewhere')
        else:
            #some error
            
    form = MyModelForm(instance=toUpdate)
    return render(request, 'somwhere2/createupdate.html', {'form':form})

The scenario is: - current model values: name="aaa", version=1,场景是:- 当前 model 值:name="aaa", version=1,

2 users open edit form, first user changes name "aaa" to "bbb", and saves, second changes name "aaa" co "ccc" and saves. 2 个用户打开编辑表单,第一个用户将名称“aaa”更改为“bbb”并保存,第二个用户将名称“aaa”更改为“ccc”并保存。 Result is "ccc", but I'd like to have some message/version conflict message... The problem is.. there is no conflict, because even if the second user can see still "aaa", while in DB there is "bbb" already... but after POST button click, the values are updated to bbb first, and version is updated, so the code is unable to see, that user2 works on old version... :(结果是“ccc”,但我想要一些消息/版本冲突消息......问题是......没有冲突,因为即使第二个用户仍然可以看到“aaa”,而在数据库中有“bbb”已经...但是在单击 POST 按钮后,值首先更新为 bbb,并且版本已更新,因此代码无法看到,user2 在旧版本上工作...:(

I'd like that versioning mechanism to prevent such scenario, but I'm unable to achieve it...我想要那种版本控制机制来防止这种情况,但我无法实现它......

How to implement it?如何实施?

I've read everything I could about django optimistic locking etc, but unable to achieve it,我已经阅读了有关 django 乐观锁定等的所有内容,但无法实现,

I think using select_for_update() might solve your problem.我认为使用select_for_update()可能会解决您的问题。 Check out this article .查看这篇文章

I was thinking of something like this:我在想这样的事情:

def updateModel(request, id): 
    toUpdate = MyModel.objects.get(pk=id)    
    if request.method=='POST':
        form = MyModelForm(request.POST,  instance=toUpdate)
        if form.is_valid(): 
            with transaction.atomic():
                try:
                     actual =  MyModel.objects.filter(pk=id).select_for_update(nowait=True).get()
                except OperationalError:
                    # raise some error 
                if (actual.version == form.instance.version):
                    form.instance.version = form.instance.version+1
                    form.save()
                    return redirect('somewhere')
                else:
                    #some error
            
    form = MyModelForm(instance=toUpdate)
    return render(request, 'somwhere2/createupdate.html', {'form':form})

I believe I've found a problem.我相信我发现了一个问题。 It's here:它在这里:

   in Model:  version =(...) editable=False

So when field is not editable - it is not placed in form, so you're loosing information about version number... And are unable to compare initially loaded version, with actual version.因此,当字段不可编辑时 - 它未放置在表单中,因此您将丢失有关版本号的信息......并且无法将最初加载的版本与实际版本进行比较。


it is still not thread-safe, but in general- blocks typical attempts to edit and save form by 2 users.它仍然不是线程安全的,但通常会阻止 2 个用户编辑和保存表单的典型尝试。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM