簡単なWebアプリケーションを作成
Webアプリケーションの基礎
Webアプリケーションの基礎技術
- ルーティング
- テンプレートエンジン
- フォーム処理
- GETメソッドとPOSTメソッド
- データベース
Flaskの特徴
- 軽量Webアプリケーションフレームワーク
- 標準で提供する機能を最小限に絞っている
FlaskでHello World
$ vi hello.py
from flask import Flask
app = Flask(__name__)
@app.route("/") # ドメイン名にアクセスした時の処理
def hello_world():
return "Hello World!"
@app.route("/about") # /aboutにアクセスした時の処理(ルーティング)
def about():
return "This is paiza"
if __name__ == '__main__': # インポートされた際にプログラムが動かないようにする
app.debug = True # デバッグモード(プログラムを変更すると自動で再起動する)
app.run(host='127.0.0.1', port=5000) # Flask起動
$ python hello.py # プログラム起動
http://localhost:5000 にアクセスすると、「Hello World!」と表示されます。
http://localhost:5000/about にアクセスすると、「This is paiza」と表示されます。
テンプレートで表示
jinja2とは、Python製テンプレートエンジンで、HTMLタグの中にPythonコードを記述できます。
jinja2は、Flaskにテンプレートエンジンとして組み込まれています。
テンプレートエンジンとは、プログラムが処理した結果とHTMLのひな型を組み合わせて、Webページを生成する機能です。
HTMLにPythonのコードを埋め込むことで、以下の利点があります。
- HTMLとしてメンテナンスできる
- コードを埋め込める
- データと見た目を分離できる
テンプレートをtemplatesディレクトリ配下に作成します。
<!-- index.html -->
<style>body {padding: 10px;}</style>
<h1>Hello Python</h1>
<p>Hello paiza!</p>
# hello.py
from flask import Flask, render_template # テンプレートを使用する
app = Flask(__name__)
@app.route("/")
def hello_world():
return render_template("index.html") # index.htmlをテンプレートとして呼び出す
if __name__ == '__main__':
app.debug = True
app.run(host='127.0.0.1', port=5000)
http://localhost:5000 にアクセスすると、index.htmlの内容が表示されます。
テンプレートの書き方の理解
# hello.py
from flask import Flask, render_template # テンプレートを使用する
app = Flask(__name__)
@app.route("/")
def hello_world():
name = "Flask"
return render_template("index.html", name_value = name) # テンプレートに「name_value」変数を渡す
if __name__ == '__main__':
app.debug = True
app.run(host='127.0.0.1', port=5000)
<!-- index.html -->
<style>body {padding: 10px;}</style>
{% if name_value %} <!-- pythonのコードは {% %} で囲む -->
<h1>Hello {{ name_value }}</h1> <!-- name_value変数を記述 -->
{% else %}
<p>Hello paiza!</p>
{% endif %}
ループ処理
# hello.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def hello_world():
name = "Flask"
players = ["勇者", "戦士", "魔法使い"] # リストを渡すこともできる
return render_template("index.html", name_value = name, players = players)
if __name__ == '__main__':
app.debug = True
app.run(host='127.0.0.1', port=5000)
<!-- index.html -->
<style>body {padding: 10px;}</style>
<h1>Hello {{ name_value }}</h1>
<p>Hello paiza!</p>
{% for player in players: %} <!-- ループでリストの要素を出力 -->
{{ player + "はモンスターと戦った" }}
{% endfor %}
■ブラウザでの出力結果
Hello Flask
Hello paiza!
勇者はモンスターと戦った
戦士はモンスターと戦った
魔法使いはモンスターと戦った
テンプレートの共通部分の分割
<!-- layout.html(共通テンプレート) -->
<style>body {padding: 10px;}</style>
<p>共通テンプレート</p>
{% block content %}
{% endblock %}
<!-- index.html -->
{% extends "layout.html" %} <!-- 共通テンプレートとしてlayout.htmlを呼び出し -->
{% block content %} <!-- 以下の部分を共通テンプレートにはめ込む -->
<h1>Hello {{ name_value }}</h1>
<p>Hello paiza!</p>
{% for player in players: %}
{{ player + "はモンスターと戦った" }}
{% endfor %}
{% endblock %}
RPGの行動選択メニューを作る
# player_menu.py
from flask Flask, render_template
app = Flask(__name__)
player = "勇者"
# メニューを表示
@app.route("/")
def menu():
return render_template("menu.html", player = player)
# あるく
@app.route("/walk")
def walk():
message = player + "は荒野を歩いていた。"
return render_template("action.html", player = player, message = message)
# たたかう
@app.route("/attack")
def attack():
message = player + "はモンスターと戦った。"
return render_template("action.html", player = player, message = message)
<!-- menu.html -->
{% extends "layout.html" %}
{% block content %}
<h1>{{ player }}のメニュー</h1>
<p>
<a href="/walk">あるく</a>
<a href="/attack">たたかう</a>
{% endblock %}
<!-- action.html -->
{% extends "layout.html" %}
{% block content %}
<h1>{{ player }}のアクション</h1>
</p><p>{{ message }}</p>
<a href="/">メニューに戻る</a>
{% endblock %}
■ブラウザでの出力結果
勇者のメニュー
あるく ⇒ リンクをクリックすると、/walk にアクセスして、「勇者は荒野を歩いていた」と表示
たたかう ⇒ リンクをクリックすると、/attack にアクセスして、「勇者はモンスターと戦った」と表示
フォーム処理の基本を身に付ける
投稿フォームを作成して、投稿したデータを表示する
# form.py
from flask import Flask, request, render_template # requestモジュールをimport
app = Flask(__name__)
@app.route("/")
def show():
message = "Hello World!"
return render_template("form.html", message = message)
@app.route("/result", methods=["POST"]) # POSTメソッドで送信
def result():
message = "This is paiza"
article = request.form["article"] # フォームの値をarticle変数に代入
name = request.form["name"] # フォームの値をname変数に代入
return render_template("form.html", message = message, article = article, name = name)
if __name__ == '__main__':
app.debug = True
app.run(host='127.0.0.1', port=5000)
<!-- form.html -->
{% extends "layout.html" %}
{% block content %}
<h1>フォーム</h1>
<p>{{ message }}</p>
<form action="/result" method="post">
<label for="article">投稿</label><input name="article" type="text" />
<label for="name">名前</label><input name="name" type="text" />
<button type="submit">送信する</button>
</form>
{{ article }} {{ name }}
{% endblock %}
フォームに値を投稿すると、POSTで受け取って表示します。
GETメソッドでフォームを作成
# form.py
from flask import Flask, request, render_template
app = Flask(__name__)
@app.route("/")
def show():
message = "Hello World!"
return render_template("form.html", message = message)
@app.route("/result", methods=["GET", "POST"]) # メソッドにGETを追加
def result():
message = "This is paiza"
if request.method == "POST":
article = request.form["article"]
name = request.form["name"]
else:
article = request.args.get("article")
name = request.args.get("name")
return render_template("form.html", message = message, article = article, name = name)
if __name__ == '__main__':
app.debug = True
app.run(host='127.0.0.1', port=5000)
<!-- form.html -->
{% extends "layout.html" %}
{% block content %}
<h1>フォーム</h1>
<p>{{ message }}</p>
<form action="/result" method="get"><!-- getメソッドに変更 -->
<labe for="article">投稿<input name="article" type="text" />
<label for="name">名前</label><input name="name" type="text" />
<button type="submit">送信する</button>
</labe></form>
{{ article }} {{ name }}
{% endblock %}
GETメソッドを使用した場合は、URLが以下のようになります。
http://localhost/result?article=XXXX&name=XXXX
ブラウザのアドレスにフォームの値が含まれてしまうので、検索フォームなどでGETメソッドはよく使用されます。パスワードなどのデータを送信する場合は、POSTメソッドを使用します。
フォームでRPGの戦闘シーンを作成
# battle.py
from flask import Flask, request, render_template
app = Flask(__name__)
players = ["勇者", "戦士", "魔法使い"]
@app.route("/")
def show():
message = "あらたなモンスターがあらわれた!"
return render_template("battle.html", message = message, players = players)
@app.route("/result", methods=["POST"])
def result():
name = request.form["name"]
message = name + "はモンスターと戦った!"
return render_template("battle.html", message = message, article = article, name = name, players = players)
if __name__ == '__main__':
app.debug = True
app.run(host='127.0.0.1', port=5000)
<!-- battle.html -->
{% extends "layout.html" %}
{% block content %}
<h1>RPGの戦闘フォーム</h1>
<p>{{ message }}</p>
<form action="/result" method="post">
<select name="name">
{% for player in playres %} <!-- players変数から要素を取り出す -->
<option value="{{ player }}">{{ player }}</option> <!-- optionタグのvalue属性にセット -->
{% endfor %}
</select>
<button type="submit">たたかう</button>
</form>
<form action="/" method="get">
<button type="submit">にげる!</button>
</form>
{% endblock %}
ドロップダウンメニューでプレイヤーが選択できるようになります。
1行掲示板を作成
投稿をしたデータを表示
下記のようなデータファイルを準備します。
# article.txt Hello World,paiza Hello Python,paiza Hello Flask,paiza 世界のみなさんコンニチハ,霧島 にゃー,ネコ
# bbs.py
from flask import Flask, request, render_template
import codecs
app = Flask(__name__)
@app.route("/")
def bbs():
message = "Hello World!"
file = codecs.open("articles.txt", "r", "utf-8") # articles.txtファイルを読み込みモードで開く
lines = file.readlines() # readlinesメソッドでファイルを読み込み、lines変数にリストで格納
file.close()
return render_template("bbs.html", message = message, lines = lines)
@app.route("/result", methods=["POST"])
def result():
message = "This is paiza"
article = request.form["article"]
name = request.form["name"]
return render_template("bbs.html", message = message, article = article, name = name)
if __name__ == '__main__':
app.debug = True
app.run(host='127.0.0.1', port=5000)
<!-- bbs.html -->
{% extends "layout.html" %}
{% block content %}
<h1>1行掲示板</h1>
<p>{{ message }}</p>
<form action="/result" method="post">
<label for="article">投稿</label> <input name="article" type="text" />
<label for="name">名前</label> <input name="name" type="text" />
<button type="submit">送信する</button>
</form>
<h2>投稿一覧</h2>
{% for line in lines: %}
{% set column = line.rstrip().split(",") %} <!-- 末尾の改行コードを削除して、set命令でカンマで分割した値を変数に代入 -->
{% for item in column: %}
{% endfor %}
{% endfor %}
<table>
<tbody>
<tr><th>投稿</th><th>名前</th></tr>
<tr><td>{{ item }}</td></tr>
</tbody>
</table>
{% endblock %}
投稿内容をテーブルで表示することができます。
投稿をファイルに保存
# bbs.py
from flask import Flask, request, render_template
import codecs
app = Flask(__name__)
@app.route("/")
def bbs():
message = "Hello World!"
file = codecs.open("articles.txt", "r", "utf-8")
lines = file.readlines()
file.close()
return render_template("bbs.html", message = message, lines = lines)
@app.route("/result", methods=["POST"])
def result():
message = "This is paiza"
article = request.form["article"]
name = request.form["name"]
file = codecs.open("articles.txt", "a", "utf-8") # ファイルを追加書き込みモードで開く
file.write(article + "," + name + "\n") # カンマ区切りで変数を代入
file.close()
return render_template("bbs_result.html", message = message, article = article, name = name)
if __name__ == '__main__':
app.debug = True
app.run(host='127.0.0.1', port=5000)
<!-- bbs_result.html -->
{% extends "layout.html" %}
{% block content %}
<h1>書き込みました</h1>
<p>{{ message }} {{ article }} {{ name }}</p>
<form action="/" method="get"><button type="submit">戻る</button></form>
{% endblock %}
articles.txtファイルに書き込んで、投稿一覧を表示できるようになりました。
