FlaskによるWebアプリ開発③~formタグでのデータのGET/POST送信

この記事は約19分で読めます。

 

前回までにやったこと

 

 

 

前回はテンプレートエンジン「Jinja2」を使って、.pyファイルで定義した変数をhtml側に渡したり、Webページの表示内容を渡された変数の内容によって条件分岐させたり、for文を使ってリストを表示するなどの方法について解説しました。

 

前回の内容は.py(app.py)⇒html側(~~.html)にデータを渡していましたが、今回からは逆にhtml⇒.pyにデータを送る方法について紹介していきたいと思います。

 

 

リクエストとは

 

Webアプリケーションでは、ログインや入力フォームに代表されるようにユーザが入力した情報を処理に利用することがよくあります。このユーザーが入力した情報をサーバー側に送ることを一般的に「リクエスト」と言います。

 

ブラウザでWebページを閲覧する際には、サーバに「このファイルを見せてください」と要求(リクエスト)しており、サーバーがレスポンスとしてhtmlを返し、それをブラウザが人間に見やすい形で表示しています。

 

このリクエストの方法(メソッド)でよく使うものにGETPOSTがあり、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)に保存

 

 

 

 

コメント

タイトルとURLをコピーしました