Python

PythonのFlaskで日付を入れるフォームを作成 ②

このページは

PythonのFlaskで日付を入れるフォームを作成 ①

の続きです

6. Flaskの構造にcss, js, htmlファイルを移動する

Flaskのフレームワークでは少し作業フォルダの構造が異なります。

さきほどのtest.htmlを「templates」フォルダに
cssフォルダ, jsフォルダを「static」フォルダに入れて下の層にします。
作業フォルダに「app.py」というPythonファイルを作成します。

作業用フォルダの中身



  |--app.py
  |
  |
  |--templates------test.html
  |
  |
  ---static----css-----bootstrap.css
            |       |
            |       |--bootstrap-datepicker.min.css
            |
            |
            |--js------bootstrap.bundle.js
                    |
                    |--bootstrap-datepicker.min.js
                    |
                    |--bootstrap-datepicker.ja.min.js
                    |
                    |--jquery-3.6.0.min.js



という構造になります。

7. Flaskのapp.pyファイルを記載する

app.pyを記載する

単純にwtformsのDateFieldを使用して日付を記入できるフォームを記載します。

from flask import Flask, render_template, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import DateField, SubmitField

app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'

class DateForm(FlaskForm):
    inputdate = DateField('日付を記入してください:', format='%Y/%m/%d')
    submit = SubmitField('提出')

@app.route('/', methods=['GET','POST'])
def index():
    form = DateForm()
    return render_template("test.html", form=form)

if __name__ == "__main__":
    app.run(port=8000, debug=True)

8. htmlファイルを作成する

template内のtest.htmlを記載します。

① css, jsのリンク先を変更する

headタグ内のcss, jsのリンクは、static以下のフォルダに指定変更する必要があります。
リンク先のアドレスを

hrefまたはsrc="{{url_for('static', filename='static以下のアドレス')}}"

で指定します。


<html lang="ja" dir="ltr">
    <head>
        <meta charset="utf-8">
        <title></title>
        <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
        <!--cssの記載-->
        <link rel="stylesheet" type="text/css" href="{{url_for('static',filename='css/bootstrap.css')}}">
        <link rel="stylesheet" type="text/css" href="{{url_for('static',filename='css/bootstrap-datepicker.min.css')}}">
        <!--jsの記載-->

        <script src="{{url_for('static',filename='js/jquery-3.6.0.min.js')}}"></script>
        <script src="{{url_for('static',filename='js/bootstrap.bundle.js')}}"></script>
        <script src="{{url_for('static',filename='js/bootstrap-datepicker.min.js')}}"></script>
        <script src="{{url_for('static',filename='js/bootstrap-datepicker.ja.min.js')}}"></script>
    </head>

    <body>
        <form method="post">
        {{ form.hidden_tag() }}
        <br>
        {{form.inputdate.label()}}
        {{form.inputdate(class="date_pick")}}
        <br>
        {{form.submit()}}
        </form>

        <script>
            $(function() {
                $(".date_pick").datepicker({
                language:'ja'
                });
            });
        </script>
    </body>

この状態で

python app.py

でapp.pyを起動し、
「http://127.0.0.1:8000/」
にアクセスします。
フォームの形はでますが、当然datepickerの設定ができていないのでカレンダーは出てきません。

② DataFieldの部分でクラスを指定し、datepickerを機能させる

wtformsのDateFieldである
form.inputdate()のところを変更します。
bodyを次のように書き換えます。


   <body>
        <form method="post">
        {{ form.hidden_tag() }}
        <br>
        {{form.inputdate.label()}}
        {{form.inputdate(class="date_pick")}}
        <br>
        {{form.submit()}}
        </form>

        <script>
            $(function() {
                $(".date_pick").datepicker({
                language:'ja'
                });
            });
        </script>
    </body>

wtformsのDataFieldである
form.inputdate(class=”中身”)のクラスの中身と
$(".中身")の.のあとを一致させます。

するとカレンダーが表示されるようになりました。

9. 入力を出力し、書き出すhtmlを作成する

app.pyではindexにアクセスしたところまでしか設定しておらず、このままではsubmitを押しても何もおきません。
日付を入力して出力する簡単なプログラムを書きます。
入力を受け取るページをanswer.htmlとしてtemplates内に作成しておきます。

app.py



from flask import Flask, render_template, redirect, url_for
from flask_wtf import FlaskForm
from wtforms import DateField, SubmitField

app = Flask(__name__)
app.config['SECRET_KEY'] = 'mysecretkey'

class DateForm(FlaskForm):
    inputdate = DateField('日付を記入してください:', format='%Y/%m/%d')
    submit = SubmitField('提出')

@app.route('/', methods=['GET','POST'])
def index():
    form = DateForm()
    if form.validate_on_submit():
        select_date = form.inputdate.data
        #formで入力された日付データをselect_dataに格納してanswerにわたす
        return redirect(url_for('answer', select_date=select_date))
    return render_template("test.html", form=form)

@app.route('/<select_date>')
def answer(select_date):
    return render_template('answer.html', select_date=select_date)

if __name__ == "__main__":
    app.run(port=8000, debug=True)

answer.html

<p>選んだ日は:{{select_date}}</p>

最終的な作業用フォルダの中身



  |--app.py
  |
  |
  |--templates------test.html
  |             |
  |             ----answer.html
  |
  |
  ---static----css-----bootstrap.css
            |       |
            |       |--bootstrap-datepicker.min.css
            |
            |
            |--js------bootstrap.bundle.js
                    |
                    |--bootstrap-datepicker.min.js
                    |
                    |--bootstrap-datepicker.ja.min.js
                    |
                    |--jquery-3.6.0.min.js



python app.py

で起動させます。

カレンダーから数字をピックアップして

送信ボタンをおすと

次のページに反映されます。

10. 注意事項

①日付の入力形式をあわせていないとエラーが起こる

日付には2021/11/1や、2011-11-1といったいろいろな書き方があります。

入力のDateFieldとカレンダーからの入力が異なると、
submitしても 
validate_on_submit()がFalseのままとなり、
結果を受けとることができません。

例えば

class DateForm(FlaskForm):
    inputdate = DateField('日付を記入してください:', format='%Y-%m-%d')

とformatを指定していると、このフィールドは
「2021-11-1」
という入力を期待します。
ところがdatepickerのカレンダーからのデフォルトの入力は
%Y/%m/%dなので
「2021/11/1」
と入力されvalidate_on_submit()はFalseのままになります。
そうなるとSubmitのボタンを押しても同じページが表示されつづけます。

② dateとdataを間違えないこと(スペルミス)

「そんな事わざわざ言われなくてもわかってるよ」

と言われそうですが、本当に間違えやすいです。注意しましょう。

Pythonはデータ解析のプログラムはエラーで止まりますが、Flaskは「動かないまま」ということが多々あります。エラーのパターンを覚えてつぶしていきましょう。