【问题标题】:Allowing users to delete their accounts leads to 400 Bad Request in Flask允许用户删除他们的帐户会导致 Flask 中的 400 Bad Request
【发布时间】:2019-01-22 01:26:04
【问题描述】:

我在设置用户帐户删除选项时遇到问题。我已经设置了一个 Bootstrap 模式以弹出保证,并且我希望“删除”按钮从数据库中删除当前用户的帐户,注销用户,并使用 Flash 消息将用户重定向到主页。但是,当我单击该按钮时,它会抛出 400 错误请求错误。不知道是不是POST方法的原因还是别的什么,所以我在这里,寻求您的帮助。我在我的应用程序中使用 PostgreSQL 以及 SQLAlchemy 和 Flask-Login(用于current_user)。这是我第一次设置这样的东西,如果我的问题不够清楚,请告诉我,以便我提供更多详细信息。此外,如果您对如何优化它有任何建议,我将非常感激听到它。以下是相关代码:

模态中的按钮:

<form action="{{ url_for('user.delete_account') }}" method="POST">
  <input type="submit" id="delete" name="delete" value="Delete" class="btn btn-danger">
</form>

路由和删除功能:

@user.route('/delete', methods=['POST'])
@login_required
def delete_account():
    if request.method == 'POST':
        if request.form['delete'] == 'Delete':

            current_user.delete()

            flash('Your account has been successfully deleted.', 'success')
            return redirect(url_for('core.home'))

我真的希望我的问题足够清楚,因为我连续 10 多个小时被这个问题困住了,我需要帮助。提前致谢。

【问题讨论】:

    标签: python post flask delete-row http-status-code-400


    【解决方案1】:

    找到解决方案:

    所以基本上,我玩了一下代码并找到了解决方案。以下是相关代码:

    首先,我创建了一个带有隐藏 CSRF 令牌的 Jinja2 宏:

    {%- macro form_tag(endpoint, fid='', css_class='', method='post') -%}
      <form action="{{ url_for(endpoint, **kwargs) }}" method="{{ method }}"
            id="{{ fid }}" class="{{ css_class }}" role="form">
        {{ form.hidden_tag() }}
        {{ caller () }}
      </form>
    {%- endmacro -%}
    

    之后我创建了最简单的表单:

    from flask_wtf import Form
    from wtforms import SubmitField
    
    
    class DeleteUserForm(Form):
        delete = SubmitField('Delete')
    

    之后我将其添加到 Bootstrap 模式中:

    {% import 'macros/form.html' as f with context %}
    
    {% call f.form_tag('user.delete') %}
      <button type="submit" class="btn btn-danger">Delete</button>
    {% endcall %}
    

    最后,我在views.py文件中修改了路由:

    @user.route('/settings/delete', methods=['POST'])
    @login_required
    def delete():
        form = DeleteUserForm()
    
        if form.validate_on_submit():
            current_user.delete()
    
            flash('Your account has been successfully deleted. Hope to see you again.', 'success')
            return redirect(url_for('user.login'))
    
        return render_template('user/login.html', form=form)
    

    这个解决方案是我能做的最好的。我希望这对其他人也有帮助。哦,我差点忘了,因为我正在编辑我的settings.html 文件,所以我还必须在我的/settings 页面路由中传递form=form 参数:

    @user.route('/settings')
    @login_required
    def settings():
        form = DeleteUserForm()
        return render_template('user/settings.html', form=form)
    

    就是这样。感谢那些也发布答案的人,我很感激。

    【讨论】:

    • 啊,所以问题是您的应用程序中有 CSRF 检查(可能来自Flask-WTF?),而您甚至没有找到您的处理程序。感谢您带回答案。
    • 确实如此。由于我仍然没有足够的经验,我只是忘记在我的应用程序中实现 CSRF ......这是第 5 次。我了解到,作为一般规则,POST 请求需要 CSRF 令牌才能工作。现在永远不会忘记这一点哈哈。
    【解决方案2】:

    编辑:事实证明,问题可能来自全局安装的 CSRF 保护层(来自 Flask-WTF 之类的东西)。如果您甚至要访问您的处理程序,进行调试将极大地帮助创建一个最小的可重现示例。


    原始最佳猜测答案:您几乎肯定会收到来自 request.form['delete'] 的 400 Bad Request 错误 - 当您尝试从 request.{form, args, values} 中获取值时,Flask 会引发此类错误' 不发送到服务器(引发的错误也是KeyError 的子类型,普通 Python 字典在相同情况下会引发:

    ({ "x": 123 })["y"]  # Raises a KeyError
    request.form["not-in-form"]  # Raises a BadRequest error
    

    所以现在的问题是,“为什么'删除'不在表单请求中?”。答案几乎可以肯定是因为您正在 JavaScript 中捕获此表单的提交事件并以编程方式提交表单......并且不包括按钮的值。包括必要的参数,或者干脆不检查表单值(甚至不检查方法,因为您已经将路由限制为仅接收POST)。

    @user.route('/delete', methods=['POST'])
    @login_required
    def delete_account():
        current_user.delete()
    
        flash('Your account has been successfully deleted.', 'success')
        return redirect(url_for('core.home'))
    

    【讨论】:

    • 谢谢你,但它对我不起作用,我仍然遇到错误。但是,我找到了另一种解决方案,并已将其发布在答案中。
    • 如果有KeyError,服务器应该返回50x。
    • 在这种情况下request.form['not-there'] 抛出的错误实际上是BadRequest的子类型( KeyError) - see the code for more details
    猜你喜欢
    • 2018-01-28
    • 2020-04-23
    • 2016-05-06
    • 1970-01-01
    • 2014-08-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多