Contents
前回までにやったこと
前回はテンプレートエンジン「Jinja2」を使って、.pyファイルで定義した変数をhtml側に渡したり、Webページの表示内容を渡された変数の内容によって条件分岐させたり、for文を使ってリストを表示するなどの方法について解説しました。
前回の内容は.py(app.py)⇒html側(~~.html)にデータを渡していましたが、今回からは逆にhtml⇒.pyにデータを送る方法について紹介していきたいと思います。
リクエストとは
Webアプリケーションでは、ログインや入力フォームに代表されるようにユーザが入力した情報を処理に利用することがよくあります。このユーザーが入力した情報をサーバー側に送ることを一般的に「リクエスト」と言います。
ブラウザでWebページを閲覧する際には、サーバに「このファイルを見せてください」と要求(リクエスト)しており、サーバーがレスポンスとしてhtmlを返し、それをブラウザが人間に見やすい形で表示しています。
このリクエストの方法(メソッド)でよく使うものにGETとPOSTがあり、Webアプリケーションを作るうえではこの2つについて理解していれば、ほとんどのものが作れるのでまずはこの2つを押さえておきましょう。
というわけで今日はflaskを使って「GET」と「POST」の流れや使い方について簡単に説明していきたいと思います。
GET/POSTの違い
GETやPOSTを利用すると、閲覧するファイルをリクエストすると同時に、フォームに入力された内容などのデータをサーバ(リクエストしたファイル)へ引き渡すことができます。GETとPOSTの特徴は以下となります。
<GETメソッド>
・HTML内で明示がない場合はGETとなる 例)ハイパーリンク(a要素)
・送信内容がURLに渡されると共に?以降が連想配列の「キー=値」として送られる(パラメータ)
・送信できるデータ情報量に制限がある
<POSTメソッド>
・入力した情報がURL上に表示されない
ちなみに、リクエストにおいて送信する内容のことを「リクエストパラメータ」と呼びます。そしてこの「リクエストパラメータ」がURLに見えるかどうかが「GET」と「POST」の大きな違いですね。
GETはhttp://url_for_taget/?key=value
、のようにurlに直接データをねじ込めるので検索結果を表すページなどに使います。http://www.google.co.jp/search?q=python
のように、GETを使ってリクエストパラメータをURLに含めると、検索結果の一覧が出ているページをブックマーク可能になります。
分かりやすい例としては、GoogleやAmazonの検索結果があります。ブラウザのURLのところを見ると訳の分からない文字列が大量に並んでいます。あれば元のURL+GETで付与した検索内容で作られたURLです。
そしてPOSTは会員登録などで名前・住所・パスワードみたいな秘匿性の高い情報を送信する際に、セキュリティの観点から利用します。まあPOSTが特段セキュリティが高いという訳でもなく、URLに送っているデータが丸だしになるGETよりはまだマシという程度で、SSL(https)などセキュリティ対策は別途必要です。
この2つの使い分けとしては、GETを使う明確なメリットがある場合以外は、基本的にPOSTを利用します。
flaskでGET処理を理解する
というわけで実際にflaskでGETとPOSTを理解していきましょう。まずは、以下のコードをapp.pyを作成してください。
めんどくさいという人はgitにコードを全部挙げているので、そちらをコピペなりダウンロードしてください
<app.py>
from flask import Flask, render_template from flask import request app = Flask(__name__) # トップ画面 @app.route('/') def index(): return render_template('index.html') # get処理の入力フォームを表示 @app.route("/request_get") def get(): return render_template('send_get.html') # getでの入力情報処理 @app.route("/receive_get", methods=["GET"]) def receive_get(): name = request.args["my_name"] if len(name) == 0: return "名前が未入力です" else: return 'あなたが入力した名前は' + str(name) + "です"
次に「templates」にsend_get.htmlを新規作成して以下のコードを記述しましょう。
<send_get.html>
<!DOCTYPE HTML> <html lang="ja"> <head> <meta charset="UTF-8"> <title>リクエストフォーム</title> </head> <body> <h1>フォームに情報を入力してapp.py側に送信する</h1> <form method="get" action="receive_get"> <label>名前: <input type="text" name="my_name"></label> <input type="submit" value="送信する"> </form> </body> </html>
app.pyのあるディレクトリに移動して$python app.py
でアプリを起動してブラウザからhttp:localhost:5000/request_getにアクセスしてみましょう。
名前を入力し[送信する]ボタンをクリックするとページが遷移し、入力した名前が表示されます。名前を入力せずに[送信する]を推すと名前を入力してくださいという警告がでます。
一応処理の流れを説明すると、まず注目したいのは@app.route("/request_get")~
の部分で入力フォームのsend_get.htmlを表示しています。
そして、ここで名前を入力し送信ボタンをクリックすると、send_get.htmlのフォームタグには<form method=”get” action=”/receive_get”>と書いてあるため、/receive_get
というURLにアクセスします。
ちなみにここで使われている<form>タグはhtmlからサーバー側に情報を送信したい時に使うタグで、フォームで入力した情報を送信すると、共にその送信に使うメソッド(GET/POST)の指定と送信先のURLを指定できます。
今回はGETで送信したいのでmethod="get"
としています。そして、action="receive_get"
と記述することで、入力データの送信先URLを[/receive_get]にすると指定しています。
そして、再びapp.py側に処理が戻って、@app.route("/receive_get", methods=["GET"])~
の部分が実行されます。
先ほど入力フォームに入力した情報はname=request.args["my_name"]
でサーバー側で受け取っています。
Flaskの関数の1つである「request」に用意されているrequest.args()
は連想配列(キーが設定に合わせて自動生成される配列)で、配列のキーはsend_get.htmlの入力フォーム(<form>~</form>)で input要素のname属性に指定した名前(今回だとname=”my_name”)になります.
なので、request.args['my_name']
とすると、html側でGETで送った入力情報をサーバー側(app.py)で取得することができます。格納されているデータはrequest_get.htmlの入力フォーム部分でユーザがテキストボックスに入力した値となります。
ここでは試しに「taro」と入力してみます。
すると、app.pyの@app.route("/receive_get", methods=["GET"])
のreceive_get()関数が実行されます。今回はtaroと入力したので、request.args['my_name']
には、’taro’というデータが入っており、変数nameにはtaroという文字型データが代入されています。
そして、その下のif文でnameの文字列はの長さは0ではないので、else以下が実行され、returnで「’あなたが入力した名前は’+str(name)+”です”」の部分が返されることで、html側には以下のように表示されます。
そして、後述するPOSTとの違いとして注目すべきはURLの部分ですね。URLが「http://127.0.0.1:5000/receive_get?my_name=taro
」という風になっています。
これはhttpメソッド(リクエスト方式)にGETを使用していると、URLに?keyvalue=〇〇という形で送信した情報が見えます。
<form>タグについて
<form>タグは、入力・送信フォームを作る際に使用します。 <form>~</form>の間に、 <input>・ <select>・ <textarea>等のタグで、 一行テキストボックス・サブミットボタン・ラジオボタン・チェックボックス・セレクトボックス・テキストボックス等のフォーム部品を配置することができます
フォームに入力されたデータは、送信ボタンを押すことでサーバー側へ送信されます。今回の場合だと、Pythonとflaskで書かれたサーバー側の管理ファイルである app.py に送信されます。
その際の送信先URLはaction属性で、データの送信方法はmethod属性で、送信するデータの形式はenctype属性でそれぞれ指定します。
ウェブサーバーへ送信されたデータのプログラム処理は、 HTMLやCSSではなく、PHPやPython・Rubyなどで処理します。
初期値はmethod="get"
です。 getの場合だとフォーム入力された内容は、action属性で指定したURLの後ろにクエスチョンマーク( ? )を付けて、それ以降続くにクエリとして送信先ページに渡されます。
これは先ほどの「http://127.0.0.1:5000/receive_get?my_name=taro
」でも分かりますね。一般的なブラウザではURLの長さに制限があるため、長すぎるデータは途中で切れてしまうので注意が必要です。
GETは短めのキーワードや番号などを送信するのに適した送信方法であり、長い文章などを送信するのには向いていません。 “get”というのは「クエリ付きURLの情報を“取得する”」という意味です。
ですがここで、method="post"
を指定するとURLの後ろに付くクエリとしてではなく、送信内容自体が本文(本体)として送信されます。 POSTの場合だと入力内容がURLに表示されることはなく、かなり長い文章も送信することができます。 “post”というのは「フォームの内容を送信先ページに“送る”」という意味です。
他にも細かい指定はありますが、これは本筋ではないのでこの辺にしておきます。<form>タグについての詳しいことは↓に書かれています。
参照:http://www.htmq.com/html5/form.shtml
flaskでPOST処理を理解する
次はPOST処理をFlaskでやっていきます。app.pyに以下のコードを追加して、「templates」にsend_post.htmlを新しく作ってください。
<app.py>
# post処理の入力フォームを表示 @app.route("/request_post", methods=["GET"]) def post_sample(): return render_template('send_post.html') # postでの入力情報処理 @app.route("/request_post", methods=["POST"]) def post_action(): if "gender" in request.form.keys(): gender = request.form["gender"] if gender == "男": sex = '男性' elif gender == "女": sex = "女性" else: sex = '性別不明' if 'age' in request.form.keys(): age_range = request.form['age'] else: age_range = '年齢不詳' return f'あなたは{sex}で{age_range}です。'
<send_post.html>
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>リクエスト使用例</title> </head> <body> <h2>ユーザー情報を入力してください</h2> <form method="post"> <input type="radio" name="gender" value="男" {{checked1}}>男 <input type="radio" name="gender" value="女" {{checked2}}>女 <input type="submit" value="送信"> <p></p> <!-- セレクトボックス --> <select name="age"> <option value="">選択してください</option> <option value="20歳未満">20歳未満</option> <option value="20-29歳">20-29歳</option> <option value="30-39歳">30-39歳</option> <option value="40-49歳">40-49歳</option> <option value="50-59歳">50-59歳</option> <option value="60-69歳">60-69歳</option> <option value="70-79歳">70-79歳</option> <option value="80歳以上">80歳以上</option> </select> </form> <p></p> </body> </html>
POSTでも、先ほどのGETと同じように、ラジオボタンのチェックした値を取得し表示しています。GETとは違ってURLの後ろにリクエストパラメーターは付与されておらず、送信した後のURLに?=~~みたいなパラメータが付いていません。
GETやPOSTで入力情報を送ることができるのはテキストボックスだけでなく、今回作成したラジオボタン、セレクトボックスなど、ユーザが選択や入力可能な情報はFlaskでだとGETリクエストの場合ならrequest.args()
、POSTリクエストの場合ならrequest.form()
で受け取ることが可能です。
なおテキストボックス<input type=”text”>の場合は、ユーザが入力した値が送られてきましたが、ラジオボタンやセレクトボックスの場合、value=””に指定した値が、request.argsまたはrequest.formに送られてきます。※セレクトボックスはvalueを指定しなかった場合、表示されている値が送信されます。
今回の場合だと
<input type="radio" name="gender" value="男" >男 <input type="radio" name="gender" value="女" >女
なので、app.pyのrequest.form["gender"]
に送られるのはvalue="男" 、value="女"
のどちらかになります。
そして、サーバー側(app.py)でif文の条件分岐で、変数に男性か女性がどちらを出力するかを決めています。また入力せずに送信した場合はelse以下の処理で性別不明と返すようにしています。その下のageの部分も性別と同じような流れになっています。
まとめ
以上がGETとPOSTの違いと、それをFlaskにおいて実装する方法です。とりあえずGET/POSTと<form>タグを理解すると、外側はそれっぽいWebアプリが作れるようになります。
<app.py>(python3.6以上で動作可能)
from flask import Flask, render_template from flask import request app = Flask(__name__) # トップ画面 @app.route('/') def index(): return render_template('index.html') # get処理の入力フォームを表示 @app.route("/request_get") def get(): return render_template('send_get.html') # getでの入力情報処理 @app.route("/receive_get", methods=["GET"]) def receive_get(): name = request.args["my_name"] if len(name) == 0: return "名前が未入力です" else: return 'あなたが入力した名前は' + str(name) + "です" # post処理の入力フォームを表示 @app.route("/request_post", methods=["GET"]) def post_sample(): return render_template('send_post.html') # postでの入力情報処理 @app.route("/request_post", methods=["POST"]) def post_action(): if "gender" in request.form.keys(): gender = request.form["gender"] if gender == "男": sex = '男性' elif gender == "女": sex = "女性" else: sex = '性別不明' if 'age' in request.form.keys(): age_range = request.form['age'] else: age_range = '年齢不詳' return f'あなたは{sex}で{age_range}です。' # テスト環境起動 app.run(debug=True)
参照:https://github.com/beginerSE/flask_form
この記事で作ったサンプルアプリケーションは私のgitにアップロードしているので、そちらをダウンロードして動かしていただけると、理解が深まるかと思います。
今回は単に<form>タグで入力された情報をhtml上にそのまま表示させるだけでしたが、ユーザー登録などでユーザー側が送信した情報を保管するためには、データベースとの接続が必要になってきます。
というわけで次回からはWEBフレームワークのflaskとsqliteというデータベースを連結させて、html側から入力した情報をデータベースに記録したり、データベースに保管されている情報をHTMLに送る方法について解説していきます。
この記事の続き→flaskによるWebアプリ開発④~SQLAlchemyでPythonとデータベースと連携させる
関連記事:Pythonでデータベース(DB)を作成・操作できる「sqlite3」の使い方
関連記事:【Python】スクレイピングした価格データをデータベース(DB)に保存
コメント
[…] ・【Python】FlaskによるWebアプリ開発③~formタグでのデータのGET/POST送信 […]