Метод 405 не разрешен при перенаправлении в Flask по маршруту POST

Я надеюсь пролить свет на то, почему я получаю ошибку 405 Method Not Allowed.

Ожидаемый результат — пользователь должен быть перенаправлен на шаблон 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, особенно по flask.redirect (документы), и искал другие примеры, но не смог найти что-то, что решило бы мою проблему.

У меня есть подозрение, что когда пользователь отправляет форму и у него уже есть обзор этой конкретной игры, запрос POST также перенаправляется на маршрут «управление».

Я проверил вкладку сети в инструментах разработчика, и это запрос GET, который подходит для этого URL-адреса.

Я думаю, что я пытаюсь сказать... Я понятия не имею, почему это происходит, поэтому не знаю, как искать решение.

Снимок экрана: вкладка «Сеть» -> «Заголовки» в инструментах разработчика: Метод 405 не разрешен при перенаправлении в Flask по маршруту POST

Консоль сервера:

[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 -

Что вы получаете в консоли сервера?

Fredericka 10.05.2022 20:42

@Fredericka Я отредактировал сообщение, чтобы включить то, что находится в консоли.

NikiT 10.05.2022 20:46

Что делать, если отзыва нет?

Henry 10.05.2022 21:15

@ Генри отзыв добавлен в базу данных. Я не включал, поскольку это не имело отношения к вопросу.

NikiT 10.05.2022 21:18

Делаете ли вы какое-либо перенаправление после добавления его в базу данных?

Henry 10.05.2022 21:20

@ Генри Да, если пользователь еще не создал обзор для этой конкретной игры, обзор сохраняется в базе данных, и пользователь перенаправляется на домашнюю страницу. На главной странице есть список всех отзывов, созданных каждым пользователем, редирект проходит без ошибок. Список обзоров еще не реализован, но в настоящее время в него жестко запрограммированы заполнители.

NikiT 10.05.2022 21:28

redirect(url_for('manage', None)) работает?

Henry 10.05.2022 21:33

Я получаю что-то другое... На странице отображается перенаправление... You should be redirected automatically to target URL: /manage. If not click the link. Не переходит к /manage, пока я не нажму на ссылку. При нажатии на ссылку правильно загружается маршрут /manage и отображается быстрое сообщение.

NikiT 10.05.2022 21:43

Это странно. документы для url_for говорит: «Переменные аргументы, неизвестные целевой конечной точке, добавляются к сгенерированному URL-адресу в качестве аргументов запроса». что, кажется, то, что происходит здесь. Передача None, кажется, позволяет избежать этого, но я не уверен, почему вы получаете сообщение о перенаправлении.

Henry 10.05.2022 21:45

@ Генри, прошу прощения, я пропустил ваш код redirect(url_for('manage', None)) выдает ошибку: TypeError: url_for() takes 1 positional argument but 2 were given Что я сделал: redirect(url_for('manage'), None) выдает в соответствии с моим предыдущим комментарием

NikiT 10.05.2022 21:49

Тогда я не уверен, в чем проблема.

Henry 10.05.2022 22:12

Итак, у меня есть «исправление» из-за того, что вы упомянули выше... «Переменные аргументы, неизвестные целевой конечной точке, добавляются к сгенерированному URL-адресу в качестве аргументов запроса». Данные формы обрабатываются, если existing_review == None - поэтому, если existing_review != None, функция возвращается до того, как данные формы будут использованы. Это означает, что «переменные аргументы» неизвестны целевой конечной точке, в данном случае маршруту /manage.

NikiT 10.05.2022 22:15
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
0
12
34
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Когда вы отправляете отзыв, используется метод POST. Затем вы перенаправляете на страницу /manage, которая не принимает POST. Запрос по-прежнему 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)

Я обновил код, как было предложено, без изменений в результате.

NikiT 10.05.2022 21:09

Попробуйте второе решение, потому что ваша форма настроена на использование методов GET.

Fredericka 10.05.2022 21:10
<form class = "col s12" action = "{{url_for('submit_review', game_id=data.id)}}" method='POST'> форма настроена на использование POST, я не понимаю, почему консоль говорит GET.
NikiT 10.05.2022 21:21

Обновлено перенаправление на return redirect(url_for('manage'), code=307). Единственное изменение в результате заключается в том, что код состояния в devtools для «11198» изменился на «307 Temporary Redirect».

NikiT 10.05.2022 21:22
Ответ принят как подходящий

Во-первых, спасибо @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'))

Другие вопросы по теме