在 POST 路由中的 Flask 中重定向时不允许使用 405 方法

405 Method Not Allowed When Redirecting in Flask within POST route

我希望阐明为什么我会收到 405 方法不允许错误。

预期结果 - 当用户尝试向他们已经添加评论的游戏添加评论时,他们应该被重定向到 manage.html 模板。

实际结果 - 显示 405 错误(方法不允许)。

管理路线:

@app.route('/manage')
def manage():
    """Renders manage.html template."""
    return render_template('manage.html')

提交审核路线:

@app.route('/submit_review/<game_id>', methods=['POST'])
def submit_review(game_id):
    """
    Add users review to database.
    """
    user = User.query.filter_by(username=session['username']).first()
    existing_review = Review.query.filter_by(user_id=user.id,
                                             game_id=game.id).first()

    if existing_review:
        flash('You have already created a review for this game')
        return redirect(url_for('manage'))
...

我试过的: 我已经阅读了一些烧瓶文档,特别是关于 flask.redirect (docs),并搜索了其他示例,但我一直无法找到解决我的问题的东西。

我有一种预感,当用户提交表单时,他们已经对该特定游戏进行了评论,POST 请求也被重定向到“管理”路径。

我检查了开发工具中的网络选项卡,它是一个 GET 请求,它是正确的 URL。

我想我想说的是...我不知道为什么会这样,所以不知道如何寻找解决方案。

网络屏幕截图 -> Headers 开发工具中的选项卡

服务器控制台:

[10/May/2022 18:43:49] "POST /submit_review/11198 HTTP/1.1" 302 -

[10/May/2022 18:43:49] "review-rating=0&review-heading=&liked-text=&disliked-text=&review-hours=1&game-name=Rocket+League&igdb-id=&igdb-summary=&igdb-cover-url=&action=GET /manage HTTP/1.1" 405 -

当您提交评论时,方法是 POST。然后你重定向到不接受 POST 的页面 /manage。该请求仍然 POST 导致错误。尝试将 POST 方法添加到您的 /manage 装饰器中。

@app.route('/manage', methods= ["GET", "POST"])
def manage():
    """Renders manage.html template."""
    return render_template('manage.html')

正如我在您的控制台中看到的那样,您的表单使用了 GET 请求?在这种情况下,您可以使用类似

redirect("/Whereever", code=307)

首先,感谢@Henry 的启发寻找解决方案。

其次,我了解到在原始问题中包含整个功能,而不仅仅是我认为可能相关的功能,可能会更快地解决这个问题。

答案.

@Henry 提到,根据 url_for() 的文档 - “目标端点未知的可变参数作为查询参数附加到生成的 URL。”

这是我对这种情况的看法。

submit_review() 函数在使用表单数据之前返回,这意味着目标端点不知道表单数据。

修复前的函数:

@app.route('/submit_review/<game_id>', methods=['POST'])
def submit_review(game_id):
    """
    Adds users review to database.
    """

    existing_game = Game.query.filter_by(igdb_id=game_id).first()

    if not existing_game:
        igdb_game_data = get_game_data_by_id(game_id)[0]
        igdb_game_artwork = get_game_artwork(game_id)
        igdb_game_cover = get_game_cover_art(game_id)

        game = Game(
            name=igdb_game_data['name'],
            artwork=json.dumps(igdb_game_artwork),
            summary=igdb_game_data['summary'],
            igdb_id=igdb_game_data['id'],
            cover_art=igdb_game_cover
        )

        db.session.add(game)
        db.session.commit()

    user = User.query.filter_by(username=session['username']).first()
    game = Game.query.filter_by(igdb_id=game_id).first()

    existing_review = Review.query.filter_by(user_id=user.id,
                                             game_id=game.id).first()

    if existing_review:
        print(request)
        flash('You have already created a review for this game')
        return redirect(url_for('manage'))

    review = Review(
        user_id=user.id,
        game_id=game.id,
        rating=float(request.form.get('review-rating')),
        heading=request.form.get('review-heading'),
        liked_text=request.form.get('liked-text'),
        disliked_text=request.form.get('disliked-text'),
        hours=int(request.form.get('review-hours')),
    )

    db.session.add(review)
    db.session.commit()

    flash('Review added successfully')
    return redirect(url_for('home'))

通过移动表单数据的使用位置,我得到了预期的结果,功能是正确的,因为如果存在同一用户对该游戏的评论,评论不会添加到数据库中。

修复后的功能:

@app.route('/submit_review/<game_id>', methods=['POST'])
def submit_review(game_id):
    """
    Adds users review to database.
    """

    existing_game = Game.query.filter_by(igdb_id=game_id).first()

    if not existing_game:
        igdb_game_data = get_game_data_by_id(game_id)[0]
        igdb_game_artwork = get_game_artwork(game_id)
        igdb_game_cover = get_game_cover_art(game_id)

        game = Game(
            name=igdb_game_data['name'],
            artwork=json.dumps(igdb_game_artwork),
            summary=igdb_game_data['summary'],
            igdb_id=igdb_game_data['id'],
            cover_art=igdb_game_cover
        )

        db.session.add(game)
        db.session.commit()

    user = User.query.filter_by(username=session['username']).first()
    game = Game.query.filter_by(igdb_id=game_id).first()

    existing_review = Review.query.filter_by(user_id=user.id,
                                             game_id=game.id).first()

    review = Review(
        user_id=user.id,
        game_id=game.id,
        rating=float(request.form.get('review-rating')),
        heading=request.form.get('review-heading'),
        liked_text=request.form.get('liked-text'),
        disliked_text=request.form.get('disliked-text'),
        hours=int(request.form.get('review-hours')),
    )

    if existing_review:
        print(request)
        flash('You have already created a review for this game')
        return redirect(url_for('manage'))

    db.session.add(review)
    db.session.commit()

    flash('Review added successfully')
    return redirect(url_for('home'))