防止Flask中的并发更新

2024-10-01 09:42:28 发布

您现在位置:Python中文网/ 问答频道 /正文

我在Flask应用程序中有一个路由/视图,我正在编辑一个现有记录,我希望确保只有在更新记录的最新版本时,我的更改才会提交到数据库

例如,我的应用程序有一个蔬菜对象,它有一个名为name的字段。“编辑蔬菜”路线/视图基于一种表单,在该表单中,名称字段首先填充蔬菜的现有值

场景1:用户A打开特定记录的“编辑蔬菜”页面。“名称”字段由现有名称“小胡瓜”填充。由于拼写不正确,用户将其更改为“小胡瓜”。但是,他们会分心,几分钟内不按保存按钮。在编辑名称和按下保存按钮之间,来自美国的同事用户B打开同一记录的页面,将名称更改为“西葫芦”并保存。我希望用户A在按下保存按钮时得到警告,甚至阻止他们更新记录,因为他们实际上不再编辑记录的最新版本

场景2:用户A返回其浏览器历史记录,直到找到之前的“编辑蔬菜”记录,在该记录中,他们最初将蔬菜的名称更改为“小胡瓜”。同样,我想要一个警告,或者阻止用户a按下保存按钮并更新记录,因为他们没有更新记录的最新版本

我是新手,在我看过的所有教程中,都没有提到这些注意事项,我也无法通过网络搜索找到解决方案,尽管这可能是因为我没有使用正确的术语进行搜索。我尝试在蔬菜对象上设置一个更新的datetime,该对象在记录更新时更新。然而,我无法像以前一样解决如何检查这个问题。似乎在更新之前,POST会重新加载这个蔬菜对象。下面是我的代码的简化版本。我正在使用烧瓶WTF和sqlalchemy

@app.route("/edit_vegetable/<int:id>", methods=["GET", "POST"])
def edit_vegetable(id):
    vegetable = Vegetable.query.get(id)
    form = VegetableForm()
    if request.method == "GET":
        form.name.data = vegetable.name
    if request.method == "POST":
        if form.validate_on_submit():
        vegetable.name = request.form.get("name")
        db.session.commit()
        return redirect(url_for("vegetable_list"))
    return render_template("edit_vegetable.html", form=form)        

正如我之前所说,我是一个新手。我目前正在学习Flask,但还没有掌握JavaScript,所以如果解决方案涉及JavaScript,我可能还不太了解它


Tags: 对象用户name版本form名称id编辑
1条回答
网友
1楼 · 发布于 2024-10-01 09:42:28

经过进一步研究,我通过以下方式实现了这一点:

我的记录上有一个更新的DateTime字段(plant.updated),因此我将其添加到表单中的一个隐藏字段:

hidden_updated_datetime = HiddenField()

然后我将其添加到我的jinja模板中

在我的视图/路径中,我添加了一个检查,以查看此隐藏字段中的值是否与POST检索到的蔬菜对象上的更新字段不同。然后重新呈现edit_vegeture.html,而不是继续更新:

if form.hidden_updated_datetime.data != str(vegetable.updated):
    flash("Update failed - not updating the latest version", "danger")
    return render_template("edit_vegetable.html", form=form)
    

请注意,由于WTForm隐藏字段是字符串字段,因此正在将vegeture.updated字段转换为字符串

我意识到,与再次获取Planet对象不同,我可能还可以以与更新的datetime字段相同的方式将id添加为隐藏字段,然后尝试使用where子句执行update语句,该语句基于隐藏表单字段中的id和更新的dateime。如果更新返回零行,我就知道记录在此期间已经更改

相关问题 更多 >