Python覚え書き >

Python FlaskでWebアプリ作成

以下、PythonのWebフレームワークである Flaskの基礎を記載する。

Flaskのインストール

アプリケーション用のディレクトリ 及び 仮想環境の作成

mkdir sample_flask
cd sample_flask
python3 -m venv .venv
source .venv/bin/activate

Flaskインストール

pip install Flask

メイン処理

flask.Flask を import するだけで使用できる。

以下、空のWebアプリケーションを作成して起動する例を記載する。

app.py

# coding: utf-8
"""サンプルアプリケーション"""

from flask import Flask

# アプリケーションのインスタンス作成
# (インスタンス生成時の引数にはアプリケーション名を指定する)
app = Flask(__name__)

# ルーティング
@app.route('/')
def index():
    return ''

# 起動(コマンドラインから flask run する場合は不要)
if __name__ == "__main__":
    app.run()

起動

環境変数 FLASK_APP でエントリポイントを指定する( コマンドラインから flask run する場合)

export FLASK_APP=app.py  # デフォルトは wsgi.py or app.py

flask run で起動

flask run
# もしくは
python3 app.py

ルーティング

ルーティングは生成したFlaskインスタンスをデコレータとして利用して記述する

基本形

@app.route('/')
def index():
    return ''

# 起動(コマンドラインから flask run する場合は不要)
if __name__ == "__main__":
    app.run()

パス(URI)を指定する

@app.route('/sample')
def sample():
    return 'sample!\n'

メソッドを限定する

@app.route('/books', methods=['POST'])
def book_create():
    return 'book create!\n'

パスパラメータを受け取る

@app.route('/books/<id>'):
def book_edit(id):
    return f'book_edit : id={id}\n'

ルーティング情報を確認する

設定済みのルーティング情報は CLI コマンドで確認できる。

flask routes

Endpoint       Methods  Rule
-------------  -------  -----------------------
book_create    POST     /books
book_edit      GET      /books/
book_list      GET      /books
hello          GET      /hello
if_template    GET      /if
inctempl       GET      /inctempl
index          GET      /
inherit_templ  GET      /inherittempl
loop_template  GET      /loop
myscript       GET      /myscript
sample         GET      /sample
static         GET      /static/
webapi         GET      /webapi

リクエストデータの受け取り方法

パスに入力したデータの取得

  • @app.route デコレータに <データ形式:項目名> と指定する事で、パスに指定されたパラメータを取得できる。
  • データ形式は省略可能
  • データ形式が合致しない場合は、404 となる
  • データ形式を指定した場合は、そのデータ型で取得される。※省略時は文字列型(str)となる

例)

# データ形式を省略する場合
@app.route('/sample1/<id>'):
def sample1(id):
    return f'sample1 : id={id}\n'

# データ形式を指定する場合
@app.route('/sample2/<int:id>'):
def sample2(id):
    return f'sample2 : id={id}\n'

<指定できるデータ形式>

形式説明
string文字列(スラッシュ以外)
int整数
float浮動少数点
pathパス(スラッシュ含む)
uuidUUIDの形式
anyあらゆるパターン

GETパラメータ(クエリ文字列)の取得

flask.request.args から GETパラメータを取得する事ができる。

from flask import request

app = Flask(__name__)

@app.route('/books', methods=['GET'])
def book_list():
    limit = int(request.args.get('limit', 10))
    return f'books get :  limit:  {limit}!\n'

結果

curl http://localhost:5000/books?limit=20\&page=1
books get :  limit:  20!

POSTデータの取得

flask.request.form から POSTデータを取得する事ができる。

from flask import request

app = Flask(__name__)

@app.route('/books', methods=['POST'])
def book_create():
    var1 = request.form.get('var1')
    return f'book create. var1: {var1}!\n'

結果

curl -XPOST --data 'var1=abc' http://localhost:5000/books
book create. var1: abc!

補足

GET用の request.args も POST用の flask.request.form も 実態は ImmutableMultiDict というオブジェクトとなっている。
なので、このオブジェクトの各種メソッドを使用して、パラメータの取得や、存在確認等を行う事ができる。
※上記のサンプルでは get メソッドを取得してデータの取得を行っている。

https://tedboy.github.io/flask/generated/generated/werkzeug.ImmutableMultiDict.html

静的ファイルの配信

static というフォルダを作成し、その配下にファイルを配置する事で静的ファイルの配信ができる。

フォルダ作成

mkdir static

ファイル配置

static/style.css

h1 {
    color:  #f00;
}

CSS読み込みサンプル

app.py

@app.route('/')
def index():
    return """<!doctype html>
<html lang="ja">
<head>
<link rel="stylesheet" href="/static/style.css" />
</head>
<body>
<h1>Hello World!</h1>
</body>
</html>"""

テンプレートエンジン(jinja2)の利用

Flaskのデフォルトのテンプレートエンジンである Jinja2 の利用方法について記載する。

公式サイトにも記載があるが、構文等は Django の影響を強く受けている為、ほとんど Django と同じ。
なので、Djangoでテンプレートを書いた事があればだいたい分かる(ぱっと見は区別がつかないくらい似てる)

http://jinja.pocoo.org/docs/2.10/templates/

テンプレート格納用のディレクトリ

テンプレートの格納先はデフォルトでは、templates 配下となっている為、プロジェクト直下に templates ディレクトリを作成しておく。

mkdir templates

テンプレートの作成

templates/hello.html

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
</head>
<body>

Hello {{name}}!

</body>
</html>

基本的な使用方法

render_template でテンプレートとなるファイルと、埋め込み変数を指定する事でレンダリング結果が取得できる。

例)

from flask import Flask, request, render_template

app = Flask(__name__)

@app.route('/hello', methods=['GET'])
def hello():
    name = request.args.get('name', 'World')
    return render_template('hello.html')

変数の展開

テンプレートに展開する変数はメイン処理側で render_template の第2引数以降にキーワード引数として指定する。

app.py

from flask import Flask, request, render_template

app = Flask(__name__)

@app.route('/vars', methods=['GET'])
def vars():
    return render_template('vars.html', var1='abc', var2='def')

テンプレート側では、{{変数名}} と記述する事で変数の内容を展開する事ができる。

templates/vars.html

var1: {{var1}}<br/>
var2: {{var2}}<br/>

条件分岐

app.py

from flask import Flask, render_template
import time

app = Flask(__name__)

@app.route('/if')
def if_template():
    time_sufix = int(str(int(time.time()))[-1])
    return render_template('if.html', time_sufix=time_sufix)

templates/if.html

{% if time_sufix % 2 %}
    Odd
{% else %}
    Even
{% endif %}

繰り返し

# テンプレート内で繰り返し処理
@app.route('/loop')
def loop_template():
    items = [ 
        {'index': 0, 'var': 'A'},
        {'index': 1, 'var': 'B'},
        {'index': 2, 'var': 'C'},
        {'index': 3, 'var': 'D'},
        {'index': 4, 'var': 'E'}
    ]   
    return render_template('loop.html', items=items)

templates.loop.html

<ul>
{% for item in items %}
<li>{{item.index}} : {{item.var}}</li>
{% endfor %}
</ul>

HTMLタグ等のエスケープ無効化

Jinja2 では XSS対応としてデフォルトで HTMLタグ等がエスケープされるようになっているが、無効化する事もできる。

app.py

@app.route('/myscript')
def myscript():
    return render_template('myscript.html', myscript='<script>alert("test!")</script>')

templates/myscript.html

{% autoescape false %}
{{ myscript }}
{% endautoescape %}

テンプレートを継承する

テンプレートを継承して必要な部分のみ上書く事も可能。
http://jinja.pocoo.org/docs/2.10/templates/#template-inheritance

以下、公式サイトのサンプルを、ほぼそのまま記載。

base.html

<!doctype html>
<html lang="ja">
<head>
<meta charset="utf-8">
<head>
    {% block head %}
    <link rel="stylesheet" href="style.css" />
    <title>{% block title %}{% endblock %} - My Webpage</title>
    {% endblock %}
</head>
<body>
    <div id="content">{% block content %}{% endblock %}</div>
    <div id="footer">
        {% block footer %}
        © Copyright Sample.
        {% endblock %}
    </div>
</body>
</html>

child.html

{% extends "base.html" %}
{% block title %}Index{% endblock %}
{% block head %}
    {{ super() }}
    <style type="text/css">
        .important { color: #336699; }
    </style>
{% endblock %}
{% block content %}
    <h1>Index</h1>
    <p class="important">
      Welcome to my awesome homepage.
    </p>
{% endblock %}

他のテンプレートを include する

他のテンプレートを include する事も可能。
http://jinja.pocoo.org/docs/2.10/templates/#include

app.py

@app.route('/inctempl')
def inctempl():
    return render_template('inctempl.html', vars=['a', 'b', 'c'])

templates/inctempl.html

{% include "./part_vars.html" %}

templates/part_vars.html

<ul>
{% for var in vars %}
<li>{{var}}</li>
{% endfor %}
</ul>

テンプレート構文の表示

raw を使用する事でテンプレートの構文をそのまま表示する事ができる。

# テンプレート内で繰り返し処理
@app.route('/loop')
def loop_template():
    items = [ 
        {'index': 0, 'var': 'A'},
        {'index': 1, 'var': 'B'},
        {'index': 2, 'var': 'C'},
        {'index': 3, 'var': 'D'},
        {'index': 4, 'var': 'E'}
    ]   
    return render_template('loop.html', items=items)

templates.loop.html

<ul>
{% raw %}
{% for item in items %}
<li>{{item.index}} : {{item.var}}</li>
{% endfor %}
{% endraw %}
</ul>

コメント

templates/comment.html

{# これはコメントです #}

その他

他にも filter や macro など、様々な機能がある。
http://jinja.pocoo.org/docs/2.10/templates/

その他

ステータスコードやContent-Typeを指定する

@app.route('/webapi')
def webapi():
    return json.dumps({'var1': 'abc', 'var2': 'def'}), 200, {'Content-Type': 'application/json; charset=utf-8'}

サンプルアプリケーション

TODO: SQLAlchemy を使用した簡単なCRUDアプリケーションの例

トップ   差分 バックアップ リロード   一覧 単語検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2019-01-05 (土) 17:39:59 (197d)