質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.37%
Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

1回答

263閲覧

Flaskでredircetが動かない

stsutsumi

総合スコア1

Flask

FlaskはPython用のマイクロフレームワークであり、Werkzeug・Jinja 2・good intentionsをベースにしています。

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

0クリップ

投稿2024/08/15 01:05

実現したいこと

ユーザ登録画面でユーザを登録後、ユーザ一覧画面に遷移して、登録したユーザを確認したい

発生している問題・分からないこと

ユーザ登録しsubmit後に、redirectが効いていないのか、ユーザ一覧画面に遷移しない。

エラーメッセージ

error

1エラーメッセージは出ておりません。

該当のソースコード

app.py

1from flask import Flask,render_template,url_for,redirect,session 2from flask_wtf import FlaskForm 3from wtforms import ValidationError,StringField, PasswordField, SubmitField 4import logging 5 6app = Flask(__name__) 7 8app.config['SECRET_KEY'] = 'mysecretkey' 9 10class RegistrationForm(FlaskForm): 11 email = StringField("メールアドレス") 12 username = StringField("ユーザー名") 13 password = PasswordField("パスワード") 14 pass_confirm = PasswordField("パスワード(確認)") 15 submit = SubmitField("登録") 16 17@app.route('/register', methods=['GET','POST']) 18def register(): 19 form = RegistrationForm() 20 if form.validate_on_submit(): 21 session['email'] = form.email.data 22 session['username'] = form.username.data 23 session['password'] = form.password.data 24 return redirect(url_for('user_maintenance')) 25 return render_template('register.html', form=form) 26 27@app.route('/user_maintenance') 28def user_maintenance(): 29 return render_template('user_maintenance.html', methods=['GET','POST']) 30 31if __name__ == '__main__': 32 app.run() 33

register.html

1{% extends "base.html" %} 2{% block content %} 3<section id="user_register"> 4 <div class="container my-5"> 5 <div class="row"> 6 <div class="col-lg-4 mx-auto"> 7 <div class="card bg-primary text-center"> 8 <div class="card-body text-light"> 9 <h3>ユーザー登録</h3> 10 <p>ユーザー情報を入力してください。</p> 11 {{ form.hidden_tag() }} 12 <form method="POST"> 13 <div class="mb-3"> 14 {{ form.username.label }} {{ form.username() }} 15 </div> 16 <div class="mb-3"> 17 {{ form.email.label }} {{ form.email() }} 18 </div> 19 <div class="mb-3"> 20 {{ form.password.label }} {{ form.password() }} 21 </div> 22 <div class="mb-3"> 23 {{ form.pass_confirm.label }} {{ form.pass_confirm() }} 24 </div> 25 {{ form.submit() }} 26 </form> 27 </div> 28 </div> 29 </div> 30 </div> 31 </div> 32 </section> 33{% endblock %}

user_maintenance.html

1{% extends "base.html" %} 2{% block content %} 3 <section id="menu"> 4 <div class="container my-3 py-3 bg-light"> 5 <div class="row"> 6 <div class="col-md-3"> 7 <a href="{{url_for('register')}}" class="btn btn-primary w-100"> 8 ユーザー登録 9 </a> 10 </div> 11 </div> 12 </div> 13 </section> 14 15 <section id="list"> 16 <div class="container my-3"> 17 <div class="row"> 18 <div class="col-md-9"> 19 <div class="card"> 20 <div class="card-header"> 21 <h4>最新のユーザー</h4> 22 </div> 23 <table class="table table-striped"> 24 <thead class="table-dark"> 25 <tr> 26 <th>ID</th> 27 <th>ユーザー名</th> 28 <th>メールアドレス</th> 29 <th>管理者</th> 30 <th>ブログ投稿数</th> 31 <th>変更</th> 32 </tr> 33 </thead> 34 <tbody> 35 <tr> 36 <td>ID</td> 37 <td>{{ session['username'] }}</td> 38 <td>{{ session['email'] }}</td> 39 <td>管理者</td> 40 <td><a href="#">ブログ投稿数</a></td> 41 <td><a href="#" class="btn btn-secondary"> 42 変更 43 </a></td> 44 </tr> 45 </tbody> 46 </table> 47 </div> 48 </div> 49 </div> 50 </div> 51 </section> 52 53 <nav class="my-2" aria-label="Page navigation"> 54 <ul class="pagination justify-content-center"> 55 <li class="page-item"><a class="page-link" href="#">前へ</a></li> 56 <li class="page-item"><a class="page-link" href="#">ページNo.</a></li> 57 <li class="page-item"><a class="page-link" href="#">次へ</a></li> 58 </ul> 59 </nav> 60{% endblock %}

base.html

1<!DOCTYPE html> 2<html lang="en"> 3<head> 4 <meta charset="UTF-8"> 5 <meta http-equiv="X-UA-Compatible" content="IE=edge"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <!-- CSS only --> 8 <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous"> 9 <!-- JavaScript Bundle with Popper --> 10 <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/js/bootstrap.bundle.min.js" integrity="sha384-MrcW6ZMFYlzcLA8Nl+NtUVF0sA7MsXsP1UyJoMp4YLEuNSfAP+JcXn/tWtIaxVXM" crossorigin="anonymous"></script> 11 <title>Yossy Inc.</title> 12</head> 13<body> 14 <nav class="navbar navbar-expand-lg navbar-dark bg-dark fixed-top"> 15 <div class="container"> 16 <a class="navbar-brand" href="#">Yossy Inc.</a> 17 <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarNav" aria-controls="navbarNav" aria-expanded="false" aria-label="Toggle navigation"> 18 <span class="navbar-toggler-icon"></span> 19 </button> 20 <div class="collapse navbar-collapse" id="navbarNav"> 21 <ul class="navbar-nav"> 22 <li class="nav-item"> 23 <a class="nav-link" href="#">ホーム</a> 24 </li> 25 <li class="nav-item"> 26 <a class="nav-link" href="#">会社情報</a> 27 </li> 28 <li class="nav-item"> 29 <a class="nav-link" href="#">お問い合わせ</a> 30 </li> 31 </ul> 32 33 <ul class="navbar-nav ms-auto"> 34 <li class="nav-item"> 35 <a class="nav-link" href="#">ブログ</a> 36 </li> 37 <li class="nav-item"> 38 <a class="nav-link" href="#">カテゴリ</a> 39 </li> 40 <li class="nav-item"> 41 <a class="nav-link" href="#">お問い合わせ</a> 42 </li> 43 <li class="nav-item"> 44 <a class="nav-link" href="{{url_for('user_maintenance')}}">ユーザ</a> 45 </li> 46 <li class="nav-item"> 47 <a class="nav-link" href="#">ログアウト</a> 48 </li> 49 <span class="navbar-text ms-3"> 50 ログインユーザー 51 </span> 52 </ul> 53 </div> 54 </div> 55 </nav> 56 57 <div class="container" style="padding-top: 4rem; padding-bottom: 4rem;"> 58 <div class="alert alert-warning alert-dismissible fade show" role="alert"> 59 flashメッセージ 60 <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button> 61 </div> 62 {% block content %} 63 64 {% endblock %} 65 </div> 66 67 <footer id="footer" class="footer text-center pt-2 bg-dark fixed-bottom"> 68 <div class="container"> 69 <div class="row"> 70 <div class="col text-white"> 71 <p>Copyright @ 2022 Yossy Inc.</p> 72 </div> 73 </div> 74 </div> 75 </footer> 76</body> 77</html>

試したこと・調べたこと

  • teratailやGoogle等で検索した
  • ソースコードを自分なりに変更した
  • 知人に聞いた
  • その他
上記の詳細・結果

以下のソースコードで、redirect(url_for('user_maintenance')) 単独での動作はできました(リダイレクトはできました。登録した内容はNoneで表示されています)
試したソースコード

# if form.validate_on_submit(): session['email'] = form.email.data session['username'] = form.username.data session['password'] = form.password.data return redirect(url_for('user_maintenance')) # return render_template('register.html', form=form)

補足

特になし

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

退会済みユーザー

退会済みユーザー

2024/08/15 09:52

> 以下のソースコードで、redirect(url_for('user_maintenance')) 単独での動作はできました(リダイレクトはできました。登録した内容はNoneで表示されています) app.pyの20行目の`if form.validate_on_submit():`がFalseになっているのでしょうか? app.pyの25行目の前にデバッグのために(25行目と同じインデントで)printを入れてみたらFalseであることが確認できますでしょうか。 エラーがあった場合にエラーの内容を画面に表示してみるのも良いかもしれません。 次のリンク先の「Validating Forms」の最後のコードを参考にregister.htmlにエラー内容を表示してみたらいかがでしょうか。 [Quickstart — Flask-WTF Documentation (1.2.x)](https://flask-wtf.readthedocs.io/en/latest/quickstart/#validating-forms)
stsutsumi

2024/08/16 04:30

ありがとうございます。 Falseになっていました。しかし、なぜFalseになっているかわからずで、 バリデーションを外すと、リダイレクトすることができました、 一旦、これで進めてみたいと思います。 助かりました、ありがとうございます!
guest

回答1

0

ベストアンサー

現象を確認しました。

現在のコードを実行すると、質問文に記載の現象が発生します。

なんらかの問題が発生しているので、原因を確認するため、 register.html に以下のコードを追加します。

html

1 </section> <!-- /sectionと --> 2 {% if form.errors %} 3 {% for n in form.errors %} 4 {{ n }}: {{ form[n].errors }} 5 {% endfor %} 6 {% endif %} 7{% endblock %} <!-- endblockの間に追加 -->

これで実行し、 http://localhost:5000/register に移動後、ユーザー名/メールアドレス/パスワード/パスワード(確認)に全てaを入れ「登録」ボタンを押します。
すると以下のエラーメッセージが表示されます。

text

1csrf_token: ['The CSRF token is missing.']

エラーが分かったので、 register.html を再確認します。
すると、以下が見つかります。

html

1 <p>ユーザー情報を入力してください。</p> 2 {{ form.hidden_tag() }} <!-- ← ここ --> 3 <form method="POST">

{{ form.hidden_tag() }}<input id="csrf_token" name="csrf_token" type="hidden" value="{{略}}">の様な要素を作成してくれます。
formタグで囲まれていないと送信されません。

と言うわけで、以下のように移動します。

html

1 <p>ユーザー情報を入力してください。</p> 2 <!-- ここにあった{{ form.hidden_tag() }}を下に移動 --> 3 <form method="POST"> 4 {{ form.hidden_tag() }} <!-- ここに移動した --> 5

この状態で、アプリを実行し直し、http://localhost:5000/register に移動後、全ての項目にaを入力し、「登録」ボタンを押します。
すると、validateに成功し(form.validate_on_submit()がTrueになり)、redirectが実行されます。

ドキュメントには書いてあるのか分かりにくいですが、 validate_on_submit() は、メソッドがPOSTで、formのvalidationが全て成功し、かつ、CSRFトークンが正しい 場合、Trueになります。

※ 上の行は実は嘘です。

https://flask-wtf.readthedocs.io/en/1.2.x/api/?highlight=validate_on_submit#flask_wtf.FlaskForm.validate_on_submit

上記ドキュメントを読むと、validate_on_submit()form.is_submitted() と form.validate()のショートカットであるという記述があります。

is_submitted()を見ると、メソッドがPOST/PUT/PATCH/DELETEである場合Trueとありますので、POST以外にPUT/PATCH/DELETEでもTrueになります。

次に、form.validate()ですが、こちらは、flask-wtfではなく、wtformsのドキュメントを参照する必要があります。
https://wtforms.readthedocs.io/en/2.3.x/forms/#wtforms.form.Form.validate
これによると、各フィールドのvalidateを呼び出してフォームを検証し、全て成功したらTrueを返すとあります。
今回のコードでは、validaterは何も設定されていないため、必ず成功し、Trueが返ります。

CSRFトークンはよく分からない感じの印象を受けますが、どのみちセキュリティ対策を考えたら必須なので、無効化せずに対応することをお勧めします。

投稿2024/08/19 08:03

FiroProchainezo

総合スコア2421

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

stsutsumi

2024/08/19 22:50

回答ありがとうございます。 試したところ問題が解決しました! ベストアンサーに選ばせていただきました。
FiroProchainezo

2024/08/20 01:21

分かりやすい、良い質問でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.37%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問