Python/Flask
webフレームワークとは[編集]
Pythonは、ホームページ作成用の言語ではないが、しかしPythonを使ってホームページを作成できるサーバーソフトウェアがある。
Flask(フラスク) と Django(ジャンゴ) というのが、それであり、ともにpythonの「フレームワーク」として、よく分類される。
だが、Flask と Django とでは性質が大きく異なる。
- Flask
Flaskはそれ自体がサーバであるので、Flaskの利用には Apache などのサーバソフトは不要である。
Flask のほうが簡素である。Flask は単に、pythonでサーバのwebサイトのプログラムを作れるようにしただけのサーバソフトのようなものであり、せいぜいテンプレートエンジンという、テキスト処理をしやすい機能を追加してあるくらいで(なお、Flaskha テンプレートエンジン Jinja を採用している)、サーバとテンプレートエンジン以外の機能はFlaskはあまり用意していない。
たとえば、会員制サイト用のログイン画面とか、Eメール登録欄とか、そういうのはFlaskでは、まったく用意されていない。
だが、そのためか、ほとんど通常のpythonの実行方法と同じような使い方で、サーバが立てられるので、入門にはFlaskが適している。
いっぽう、Djangoや PHPフレームワークのLaravel などを使うと、管理用のフォルダが多く造られたりするので、フォルダ群の構造を把握するのが大変である。
しかし、Flaskの場合、そのような管理用フォルダ群は存在しないので、初心者にとっては、さっさとサーバを直感的操作できる利点がある。
なので、もし作ろうとするサイトが、会員サイトや商品取引サイトなどの技術的に難しいサイトではなく、単に一般のHTMLで文字列や画像を表示をするだけのwebページを作るだけなら、Flaskはサーバを立てるための良い選択肢のひとつであろう。
Flaskのように、必要最小限に近い機能だけを厳選したようなwebフレームワークのことを俗に「軽量フレームワーク」(英語ではマイクロフレームワーク micro framework)という。
- Django
いっぽう、Djangoは大規模なwebサービス作成を前提としており、そのためかフォルダの管理方法が決まっていたりして、それを守らないとエラーになるので、初心者にはやや敷居が高い。
Djangoのように、大規模なwebサービス作成を想定したようなwebフレームワークのことを「フルスタックフレームワーク」という。
Djangoを使う利点として、ログイン画面やEメールアドレス入力欄などユーザーのよく使う機能はあらかじめ用意されているので、そのおかげで集団作業では個々人のスキル差による品質のバラつきを無くせるなどの利点があるので、ビジネス用途などでは用いられる場合も多い。
- テンプレートエンジン
また、Flaskの別の用途として、HTMLのテキスト中(bodyタグなどの中身)にif文やfor文を組み込んで表示を制御するなどの拡張をする事ができる(いっぽう、JavaScriptだと、HTMLをその <script>タグ 〜 </script>タグ 内から制御するだけならJavaScriptでも可能だが、しかしHTMLのbodyタグなどテキスト部分そのものの内部に組込むことは(JavaScript)では出来無い)。
このようなFlaskによるHTMLの拡張の仕組みは、Flaskのテンプレートエンジン Jinja を利用したものである。
ここでいうテンプレートエンジンは、文字列の置き換えなどをする事のできるエンジンである。たとえば
私は {{a}} です。
などとHTML本文中に書いておき、別の場所で
a = "Tom"
とか書いておけば、webブラウザでの閲覧などの表示の際には
私は Tom です。
にFlaskなどのサーバが自動的に文章を置き換えてくれるような機能である。
純粋なHTML規格には、2020年の今のところ、このようなテンプレート的な機能は無い。
もっとも、Flaskだけでなく、Djangoや、PHPフレームワークのLaravelにも、それぞれのテンプレートエンジンは存在しており、if文などの機能が使えるが、しかし、Djangoなどは管理用フォルダ群などの適切な管理が必要であるので、もし単にテンプレートエンジンを使いたいだけなら、Djangoなどは大掛かりである。鶏肉を切るのに牛刀を用いるようなものであろう。また、かつて、JavaScriptのwebフレームワークであるJQueryにも、似たような、HTMLにif文やfor文などを埋め込みできるテンプレートエンジン Jquery templates が存在していたが、現在は廃止され、現在では後継の JsRender がそのようなJavaScript用のテンプレートエンジンである。
Python自体に、「テンプレート」という、文字列を置き換える機能がありますが、Flaskのテンプレートエンジンに採用されているJinjaは、python本体のテンプレートエンジンを流用たものではなく、独自に実装したものです[1]。
Django や別ページで説明するPHPフレームワークなどでもそのようなHTML拡張は可能であるが、単に手軽にHTMLをif文導入などで拡張したいだけなら、軽量フレームワークでFlaskで拡張するのが、もっとも手軽であろう。
いっぽう、純粋な Apache 単体だと、このテンプレートエンジンの機能が無い。(Apache を拡張したツールでテンプレートエンジン導入ずみのwebサーバは存在するが、しかし純粋なもともとのApacheとは別のツールである。)
なお、DjangoやFlaskなどをApache上で動かす事も可能だが、いくつかの流儀がある。ひとつの方法は、CGIを使う方法である。CGIを使うため、Apacheの設定ファイルを書き換える必要が少々あるが、よく知られている技術なので、検索ですぐに見つかるだろう(wikibooksのどこかにも、ApacheでのCGI利用のための設定書き換えの解説はある)。
他の方法では、mod_wsgi という特殊ソフトを使う方法があるが、しかしApacheの設定を書き換える必要があり、初心者には敷居が高い。mod_wsgi を使わなくても、CGIを使う方法でApache上でPythonを使えるし、Pythonに限らず他のほぼ全てのプログラミング言語でも、CGIは利用できるので、なるべくCGIを使う方法が初心者には将来的に応用が聞いて良いだろう。
しかし、商用サイトなどでDjangoを使う場合、セキュリティなどの理由から、Apache上でDjangoを動かす事が望まれている。
もし単に Apache 上で通常のPythonコードを動作させたいだけなら、Apache サーバのCGI技術でPythonの利用が可能だが(CGIを使えば、原理的には全てのプログラム言語を、サーバ上で動かせる)、しかしDjangoなどのフレームワークと連動させる仕組みが素のApacheのCGIには無いので、追加で mod_wsgiという特殊なソフトが必要になるのである。
なお、テンプレートエンジンを使うと実行速度がやや遅くなる欠点がある(テキスト表示の際に、いちいちテンプレート置き換えの有無を調べたりするので)。しかし、ある程度の大規模なオープンソース等のコミュニティのwebサイトは、もとから外国語対応などの事情もあり、翻訳のためになんらかのテンプレートエンジンまたは類似のツールを既に導入していたりするのが当然である(世界の大手サイトなどでは、英語を日本語に置き換えたり等のテンプレートがある)。
テンプレートエンジンを使わずに、いちいち日本語版サイト、英語版サイトなどを別ページとして作ってしまうと、たとえば英語版サイトのレイアウトを更新した場合に、日本語版はレイアウトが自動更新されずに前のレイアウトのままだったりするので、そういう更新ズレの原因になりかねないので、テンプレートエンジンを使ってレイアウト等は一括のページにしてしまうほうが、メンテナンスしやすい場合もある。
またなお、W3CのHTMLの規格では、テンプレートエンジンのように、HTML内で制御的なことを行うのは避ける方針である。(なるべく制御的な事は、W3CはJavaScriptまたはPHPなど(HTMLでない)プログラム言語側で行わせる方針である。レイアウトとそれ以外のロジックを分離し、HTML側ではレイアウトのみを指定させようという感じの方針をW3Cはとっている。)
つまり、実際の世界のwebプログラマーのコミュニティは、HTMLの規格に逆らっている。しかし、そもそもHTML自体に、HTMLタグという制御構造が存在しているのだから、程度問題である。だいたい、レイアウトのためにif文やfor文などを使う場合、そのif文などはレイアウトなのかロジックなのかという疑問もある(W3Cにとっては、if文などはどんな目的でもレイアウトではないという方針なのだろうか、W3C規格上ではHTML側にif文を埋め込む事はできない)。
もっとも、さすがにHTML側にif文やfor文で何十行もあるようなコードを書くのは、かえってコードの仕組みが分かりづらくなりかねないので、HTML側のif文/for文には、なるべく短めのif文やfor文のような簡潔な処理だけを書くべきである。(こういう事情もあるので、W3Cが制御的なことをなるべくJavaScript側/PHP側のような非HTML側で行わせようとするのも、妥当ではある。)
- python以外の他言語には、軽量フレームワークの組み込み済みテンプレートエンジンが無い、もしくは気運が乏しい
なお、PHPではLaravelというwebフレームワークとして有名だが、しかしlaravelはフルスタックフレームワークであり、軽量フレームワークではない。PHP界隈で軽量フレームワークを謳っている slim フレームワークには、標準備え付けのテンプレートエンジンが無いので、Flask/Jinjaのような事は標準設定では出来無い(外部のテンプレートエンジン(TwigやSmartyなど)を追加することはできるが、追加のためさまざまな設定が必要になってしまう)。cakePHPやfuelphpも同様であり、テンプレートエンジンとの連携の話題を寡聞にして聞かない。
なお、PHP のLaravel のテンプレートエンジンは Blade というものである。またなお、PHPの中枢部の実装を開発しているZend社のフレームワーク製品群は、そもそも有料製品である(ネットにある「無料版」とは、30日間の試用版)。
つまり、2020年の現在、webテンプレートエンジンを使いたいなら、そもそも PHP ではなく Python を使うほうが合理的である。
2020年の今のところ、
- 軽量webフレームワーク + テンプレートエンジン + サーバ機能組み込み済み
という組み合わせに目をつけているのは python の Flask と、Flaskの元ネタになったpython製フレームワーク Bottleくらいしか、そういった話題を聞かない。
実は Bottle というPython用フレームワークもあり、Bottle 標準のテンプレートエンジン SimpleTemplate Engine というのがあり、Bottle標準テンプレートエンジンでもHTMLにif文やfor文などを埋め込めるのだが、しかしテンプレートエンジンの使い方が、DjangoやFlaskとやや違っている(FlaskとDjangoのテンプレートエンジン文法はほぼ共通)。Bottleの標準テンプレートエンジンだと、if文などをHTMLに埋め込む際、
<!-- これはBottle用です. -->
% if フラグ:
表示の切り替えしたい文章
% end
のような方式である。Bottleだと、if文の終わりはendifではなく「end」だし、for文の終わりも「end」である。また「% if フラグ %」ではなく(%でくくるのではなく)、「%」で始まる行をテンプレートエンジンへの命令とする方式である。
HTMLのタグ文法の発想との近さと比べれば、Bottleテンプレートエンジン文法よりもFlaskテンプレートエンジン文法のほうが、HTMLのタグの発想に近い。なので、HTMLユーザーにとっては、Flaskのほうが習得が簡単であるので、集団作業の場合にFlaskのほうがスキルに応じた分業をしやすいメリットがある。(集団作業なら、Pythonの文法を知らない新人HTMLユーザーでも、Flaskのほうならwebページの編集しやすい。)
なので初学者が今からPython用フレームワークを学習するなら、BottoleよりもFlaskのほうがDjangoと知識を共有できるし、Flaskのほうがテンプレートエンジン文法がHTML文法に近いので、これからの初学者はFlaskを学習するほうが効率的である。
なお、Flaskには無く Bottleにしかない機能として、Bottleはコード内にPythonのコードを<% 中身 %> で埋め込める。
さて、別言語でフレームワークのある言語を見てみると、 JavaScriptの場合では、実は node.js などのサーバ用JavaScriptを使わなくても、Apache上でサーバを立ててそのHTMLにJavaScriptを書いただけでも、webブラウザ(Firefoxなど)でのアクセス時にJavaScriptを実行してくれる。しかし、ブラウザのバージョンや種類などによって処理結果が異なる可能性が生じてしまうので、できれば node.js などのサーバサイド JavaScript実行環境でサーバー立てするほうが望ましい。
そして、node.jsはあくまで実行環境に過ぎず、テンプレートエンジンではないし、テンプレートエンジンを組み込んでいないので、テンプレートエンジンを使うためにはサーバなどに追加の設定が必要になり、少し敷居が高い。さらに、そもそもnode.jsは本来はサーバ用ツールではなく、あくまで本来はJavaScript実行環境なので、node.jsをサーバ化するために、追加のモジュール設定などが必要になり、やや手間である。
なお、単にサーバを立てるだけなら、そもそもwebフレームワークは不要であり、Python以外の別のプログラム言語である PHP や Perl でもApacheサーバと連動でき、比較的に簡易にホームページなどをサーバで作ることができる。
- http.server
このほか、素のPython単体に、http.server という簡易的にサーバを建てるモジュールがあるが、しかしこれは動作確認用のためのモジュールである。実用では使い物にならないと考えられいるし、開発者たちに、そのような実用化のための転用の意図もなさそうである。
なお、終了するには、キーボードで
CTRL キー + cキー
の同時押しで終了する。
Flask[編集]
では、このようなテンプレートエンジンを活用する意味もこめて、Flaskの学習をしよう。(正直、もし単にwebサーバを立ち上げたいだけなら Apache で充分である。わざわざ Flask を使う理由と目的とは、テンプレートエンジンなどの apache には無い機能を使う理由などからである。)
読者は、(「Flaskを学ぼう」ではなく、)HTML用の「テンプレートエンジンという新技術を学ぼう」と思ってもらいたい。
ツールの流行なんてすぐ変わるので、Flaskが数年後も流行してるかどうかは不明であり、ひょっとしたら将来は別のwebサーバソフトに流行が変わってるかもしれない。しかしHTML用「テンプレートエンジン」という発想は、webサーバソフトの種類とは無関係に今後も生き残り続ける可能性が高いからである。
Flaskのインストール方法[編集]
Pythonのパッケージマネジャーである pip を使いインストールする。
Fedora Linux の場合シェルで
sudo dnf update
sudo dnf search pip
を実行し、pip を名前に含むパッケージの一覧を表示し、その中から python3-pip を選びインストールします(一覧にあるDescriptionsを確認してパッケージを選びます)。
sudo dnf install python3-pip
pipがインストールされたら、flask をインストールします。
$ sudo pip install flask
Collecting flask
Downloading Flask-2.0.2-py3-none-any.whl (95 kB)
|████████████████████████████████| 95 kB 4.2 MB/s
Requirement already satisfied: Jinja2>=3.0 in /usr/local/lib/python3.10/site-packages (from flask) (3.0.1)
Collecting Werkzeug>=2.0
Downloading Werkzeug-2.0.2-py3-none-any.whl (288 kB)
|████████████████████████████████| 288 kB 12.6 MB/s
Requirement already satisfied: click>=7.1.2 in /usr/local/lib/python3.10/site-packages (from flask) (8.0.3)
Collecting itsdangerous>=2.0
Downloading itsdangerous-2.0.1-py3-none-any.whl (18 kB)
Requirement already satisfied: MarkupSafe>=2.0 in /usr/local/lib/python3.10/site-packages (from Jinja2>=3.0->flask) (2.0.1)
Installing collected packages: Werkzeug, itsdangerous, flask
Successfully installed Werkzeug-2.0.2 flask-2.0.2 itsdangerous-2.0.1
$ flask --version
Python 3.10.1
Flask 2.0.2
Werkzeug 2.0.2
Linuxの場合、インストールに管理者権限が必要なので、普通は先頭に sudo がつく。
起動の方法[編集]
原理的な起動方法[編集]
まず、下記のコード
- ファイル名「app.py」
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello World"
@app.route('/')
というのが見慣れないかもしれませんが、これはデコレータというpythonの文法の機能のひとつであり、デコレータとは単に、関数の前後に処置を追加した新関数を返す機能です。(詳しくは『Python/関数』で説明しています。)
あとは定型文ですので、気にしないでください。def なんとかは、単なる関数です。冒頭のfrom は、単なるモジュールのインポートです。
__name__ というのは、Pythonのシステム変数のひとつです。
上記コードは、おおむね下記のような処理をしています。
# モジュールのインポート
from flask import Flask
# Flaskアプリの呼び出し・作成
app = Flask(__name__)
# デコレータによるルーティング
@app.route('/')
# 関数
def hello():
return "Hello World"
起動の手順
- さて、上記コードをファイル名「app.py」で保存します。このファイル名でないと、いけません。原理的に使う場合は、そういう仕様です。(後述の実用的な起動方法でなら、ファイル名を変えることもできるが、とりあえず、原理的な軌道方法ではファイル名はこれでないといけない。)
- そして、ホームフォルダに「FLASK_APP」というフォルダを作ります。
- さらに、このフォルダの中に、さきほど作成したファイル「app.py」を入れます。つまり、フォルダ「FLASK_APP」内にあるファイル「app.py」を、flaskが読み取る仕組みになっています。
- さらに、コマンドラインで、コマンドの現在位置を「FLASK_APP」内に移動します。つまり、移動コマンド
cd FLASK_APP
です。 - ここまで来たら、あとは下記の起動コマンド
flask run
で起動すると、下記のようなメッセージが出ます。
* Environment: production WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead. * Debug mode: off * Running on http://127.0.0.1:5000/ (Press CTRL+C to quit) 127.0.0.1 - - [04/Aug/2020 14:08:09] "GET / HTTP/1.1" 200 - 127.0.0.1 - - [04/Aug/2020 14:08:09] "GET /favicon.ico HTTP/1.1" 404 -
- 実行結果
上記の起動手順の後、webブラウザ(Firefoxなど)で、
http://localhost:5000/
にアクセスすると、
Hello World
と表示されているwebページが表示されます。
Pythonにかぎらず localhost ローカルホスト というのは、自分のパソコン内にあるwebサーバにアクセスする場合の自サイトの事であり、どのプログラム言語でも IPアドレス 127.0.0.1 が割り当てられています。
- 終了の方法
サーバを終了するには、キーボードでボタン
CTRL+C
(CTRLキーとCキーの同時押し)です。
- 次回以降の起動方法
cd FLASK_APP flask run
で起動する。動作確認のため、さらにwebブラウザで
http://localhost:5000/
にアクセスして、動作確認。
簡単な起動方法[編集]
実はFlaskには、もっと簡単にサーバ起動する方法があります。
- hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello World"
app.run() # これが新規に加わっている
のように、app.run() を加えたコードを、ホームフォルダに起きます。
あとは、コマンドラインで上記コードを実行すれば、つまり
python hello.py
で実行すれば、サーバが立ち上がります。
あとは、Webブラウザで localhost:5000 にアクセスすれば、ページが見れます。
- 終了の方法
サーバを終了するには、キーボードでボタン
CTRL+C
(CTRLキーとCキーの同時押し)です。
実用的な起動方法[編集]
実用的には、下記のようなコードになります。
ホームフォルダに、ファイル名は何でもいいので、たとえば hello.py
- ファイル名「hello.py」
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello World"
if __name__ == '__main__':
app.run()
とつけて、上記コードをホームフォルダに保存します。
その後、ホームフォルダにいる状態のコマンドラインで、単に
python hello.py
で実行すると、webサーバが起動します。
- 実行結果
上記の起動手順の後、webブラウザ(Firefoxなど)で、
http://localhost:5000/
にアクセスすると、
Hello World
と表示されているwebページが表示されます。
- 終了の方法
サーバを終了するには、キーボードでボタン
CTRL+C
(CTRLキーとCキーの同時押し)です。
- 解説
if __name__ == '__main__':
というのは、実態の意味は、「このコードの書いてあるファイルは、モジュールではない」という宣言です。
なお、このif文の本来の意味は、
「システム変数 __name__ が 文字列'__main__' であれば」という意味です。
__name__ というのは、Pythonのシステム変数のひとつです。コマンドラインから起動した場合、システム変数 __name__ に __main__ が入る仕様です。
一方、その他の場合には、 __name__ にはファイル名が入ります。
たとえば
- test.py
print(__name__)
というファイルを、対話モードで起動して、インポートしてみると(コマンドimport test.py
test
とファイル名が表示されます。
一方、対話モードでなく、素のコマンドラインで python test.py で起動すると
__name__
と表示されます。
実質的には if __name__ == '__main__':
とは、
「このコードがアプリケーションとして実行されている時にだけ、」という意味の条件です。
Python では、アプリとして実行していなくても、import文でpyファイルをインポートした場合にもコードの中身が実行されます。
なんと、単なるpyファイルでも、モジュールになってしまいます。
なので、実用的にはimport文でインポートした場合にはサーバを起動しないように、命令する必要があるのです。
- インポートでサーバ起動
上記の解説だけではわかりづらいでしょうから、いっそ実際にインポートでサーバを起動してみましょう。
まず、いったん立ち上げたサーバを CTRL + C で終了しましょう。 また、前回のサーバの名残りがメモリ中に残っている場合があるので、いったんコマンドラインを exit で終了しましょう。
そして
- hello.py
from flask import Flask
app = Flask(__name__)
@app.route('/')
def hello():
return "Hello World"
app.run() # これが新規に加わっている
というif文のないコードを書きましょう。
コマンドラインをまた立ち上げて、「 python 」とだけコマンドを入力して pythonインタプリタモードに移りましょう。
そして、
import hello.py
とだけコマンドを実行して、hello.py をインポートしましょう。
この時点で、サーバが立ち上がってしまい場合があります。(立ち上がらない場合、いったんコマンドラインを終了して、再度、試してください。)
なので
localhost:5000
にアクセスすると、ホームページが見れてしまいます。
なお、コードに
if __name__ == '__main__':
を追加すると、そもそもインポートできなくなる。(FEdora32 上の Python で確認。)
テンプレートエンジンの利用法[編集]
では、肝心のFlaskのテンプレートエンジン(Jinja)の利用法です。
まず、文字列を置き換えしたいHTMLファイルを、フォルダ名
templates
という名のフォルダに入れなくてはいけません。
そうしないと、FlaskやJinjaが対象HTMLを読み取れない仕様です。
python側のコードは下記のようになります。
- okikae.py
from flask import Flask, render_template
app = Flask(__name__)
@app.route('/')
def hello():
return render_template('test.html', item="pencil" )
if __name__ == '__main__':
app.run()
テンプレートエンジンを使うには、import で render_template をインポートする必要があります。
関数名は、hello()でも、aiueo()でも、なんでも構いません。
ただし、HTMLのファイル名(たとえばtest.html)と関数名が重なると(関数test()などのように)まぎらわしいので、重ならないように注意してください。
HTMLのほうは、
- test.html
This is a {{ item }}.
のように、文章を書いてください。なお、このようにテンプレートの書かれたHTMLファイルのことを、一般に「テンプレートファイル」と言います。Flaskだけでなく、PHPフレームワーク界隈などでも同様に「テンプレートファイル」という言い回しをするので、覚えましょう。
本wikiでは、各種の設定ファイルなどとの区別のため、「テンプレートHTML」とか「テンプレートHTMLファイル」などと表現する場合もあるかもしれません。
HTMLファイル名は、python側コードにある render_template()
の第一引数と同じものにしてください。
そして、このHTMLファイルを、templates フォルダに入れるのを忘れないでください。(もしtemplatesフォルダに該当HTMLを入れないと、flaskが読み取れずに、ブラウザでの表示の際にエラーになります。)
あとは、コマンドラインで、さきほど作成したokikae.py を実行してください。
- 表示結果
This is a pencil.
のように、テンプレート部分が置き換えて表示されます。
もし、ミスをしてサーバが立ち上がらなくてコードやHTMLを書き換える場合、いったん CTRL + C でサーバを終了しないと、更新が反映されません。なので、いったん CTRL + C でFlaskサーバを終了してください。
さて、テンプレートの置き換えだけなら、素のpythonでも可能です。
では次に、素のpythonでは困難・不可能な、if文をHTMLに埋め込む処理をやりましょう。JavaScriptでも、簡易な方法では不可能ですので、Flaskを使う利点がここにあります。
Jinjaの制御構造[編集]
Jinja とは、Flaskにインストールされているテンプレートエンジンです。
FlaskでHTMLにif文やfor文などの制御構造を埋め込るのは、JinjaとFlaskの連動によるものです。
条件分岐[編集]
Flaskのif文埋め込みなど[編集]
基本のフラグ方式[編集]
まず、テンプレートHTML側を、下記のように書きます。
{% if flagPen %}
I have a pen.
{% endif %}
{% if flagBook %}
This is a book.
{% endif %}
FlaskでテンプレートHTMLにif文やfor文などを埋め込む場合は、{{ 制御文 }}
ではなく、{% 制御文 %}
のように、カッコの内側が%に変わりますす。
なお、あくまでHTMLなので、インデントは不要です。
どこかの他プログラム言語のフレームワークとは異なり、Flaskではif文などの埋め込みの際にはHTMLタグをいじる必要は無いです。
なので、上記コードは
{% if flagPen %}
I have a pen.
{% endif %}
{% if flagBook %}
This is a book.
{% endif %}
のようにインデントせずにHTMLを書いても、構いません。
Flask/Jinja では、if文ブロックの終わりに {% endif %}
が必要で、for文ブロックの終わりには {% endfor %}
が必要になります。
つまり書式は、
{% if フラグ用の変数 %}
制御対象の文字列
{% endif %}
です。
なお、 {% if フラグ用の変数 %}
や {% endif %}
などのように、テンプレートで制御構造を指定しているものを、テンプレートタグという場合もあります。 Flaskに限らず、PHPのフレームワークの界隈などでも、同様に「テンプレートタグ」という言い回しをする場合も世間ではあるので、覚えておきましょう。
なお、フレームワークによっては、 テンプレート:% item %
のような通常のテンプレートのことを「テンプレートタグ」という場合もあります。
本wikiでは区別のため、もしかしたら場合によっては「テンプレート制御タグ」みたいに {% if フラグ用の変数 %}
などのことを言う事もあるかもしれません。
さて、python側のファイルは、たとえば下記のようになります。
from flask import Flask, render_template
app = Flask(__name__)
flagBook = True
flagPen = False
@app.route('/')
def hello():
return render_template('test.html',flagBook=flagBook, flagPen=flagPen )
if __name__ == '__main__':
app.run()
HTML側で容易したフラグ変数については、真または偽を決定しなくてはなりません。
また、とても醜い(みにくい)書式ですが、(初心者がコードを一目みても、内容を推測しづらいので、醜い)
render_template('test.html',flagBook=flagBook, flagPen=flagPen )
の第2引数と第3引数のように、
render_template('test.html',フラグ名1=フラグ名1, フラグ名2=フラグ名2 )
のように、引数にフラグを自分自身に代入する書式で書かなければなりません。
おそらく、内容は、
render_template('test.html', 置換する文字列名1=フラグ1の真偽値, 置換する文字列名2=フラグ2の真偽値 )
のような処理をしているものだと思われます。
おそらくですが、テンプレートに引き渡される変数の種類が、辞書型や配列型であるか、それとも一般の変数かの区別のために、こういう醜い書式にしていると思われます。(なぜなら、辞書型や配列型だと、こういう醜い書式ではないので。)
さて、手本のHTMLでは説明の簡略化のため
I have a pen.
のようなHTMLタグの無い文章にしましたが、別にHTMLを使ってもいいのです。HTMLタグは単なるテキスト文字に過ぎません。
このほか、Flaskのif文では特別に、
つねに真で表示されるハズの {% if True %}
や、つねに表示されないハズの {% if False %}
が使える。
変数方式のif文[編集]
{% if (x == 1) %}
I have a ball-pen !
{% endif %}
{% if (x == 5) %}
This is a book.
{% endif %}
のように、ifのあとに変数を含む条件式を書くことも可能です。
この場合、pythonファイル側では、下記のように、その変数を render_template で下記のように渡す必要があります。
from flask import Flask, render_template
app = Flask(__name__)
x = 1
@app.route('/')
def hello():
return render_template('test.html',x=x )
if __name__ == '__main__':
app.run()
- 実行結果
I have a ball-pen !
きちんと、条件を満たしている (x == 1)
のifブロックだけが表示されている事が分かります。
set による変数定義[編集]
if文にかぎった事ではないのですが、Jinja では set
命令で、HTML側で変数を定義できます。いちいちpythonファイル側をいじる必要なく、気軽に変数を定義することもできます。
書式は
{% set 変数 = 値 %}
です。
どこかの他プログラム言語フレームワークとは異なり、Flaskでは、setによる変数の作成をできる場所については、基本的にHTMLファイル中のどこでも行えます。
- コード例
{% set langMode = "ja" %}
{% if (langMode == "en" ) %}
This is a book.
{% endif %}
{% if (langMode == "ja" ) %}
これは本です。
{% endif %}
- 表示結果
これは本です。
繰り返し[編集]
for文[編集]
下記のように、HTMLを書いて、実行してください。
{% for n in range(4) %}
{{ n+100 }}<br>
{% endfor %}
pythonファイルは、先ほどのif文のファイルを流用する事ができます。
- 実行結果
100 101 102 103
この for 文のように、HTML側のfor文で変数を定義してしまう事が可能です。(いちいち、python側のファイルで、nを定義する必要は無いのです。)
また、テンプレート内で計算が可能です
Flask/Jinja の for in range 構文の使い方は、python本体のfor in range 構文の規則と同じです。
「マクロ」という名の関数[編集]
Jinja macro というのを用いて、関数のように、呼び出して使えるものを定義できます。
マクロの定義の書式は、
{% macro マクロ名(引数名) %}
処理内容
{% endmacro %}
マクロの呼び出しかたは、単に一般のJinjaテンプレートと同様に、
{{ マクロ名(値) }}
のように、引数をつけてテンプレート中にマクロ名を書けばいい。
- コード例
{% macro func(arg) %}
<span style="color:blue"> {{ arg }} </span>
{% endmacro %}
{{ func("おはよう") }}
- 実行結果
青い色で
- おはよう
と表示される。
辞書型のテンプレート変換[編集]
制御構造にばかり目が行きがちですが、単なるテンプレート置き換えのテンプレート変数を記述する際に、変数で1個ずつ渡す方法の他にも、辞書で一括に渡すこともできます。
- python側
from flask import Flask, render_template
app = Flask(__name__)
@app.route("/")
def hello():
dic = {"item": "golden pencil", "pet": "dog"}
return render_template("test.html", dic=dic)
if __name__ == "__main__":
app.run()
で、関数定義の中に、辞書 dic = {"item": "golden pencil", "pet": "dog" }
を埋め込み、
さらに、render_template('test.html', dic = dic )
の第2引数の右辺と左辺のように、
render_template('test.html', 辞書用変数 = 辞書名 )
としておきます。
そして、テンプレートHTMLファイル側には
This is a {{ dic.item }}.<br>
I have a {{ dic.pet }}.<br>
のように、さきほど作った辞書用変数と、辞書のキーとの組み合わせを、それぞれのテンプレート呼び出しに書いておきます。
- 表示結果
This is a golden pencil. I have a dog.
Django や PHP系フレームワークでも、方法はやや違いますが、辞書型の引渡しができて、似たようなテクニックを使うので、ぜひ、Flaskでも辞書型の引渡しの方法を習得ておきしましょう。
(※ 間借り)Django[編集]
インストール方法など[編集]
※ Django について、いちいちスタブを専用ページで作るのは憚るので、Flaskのページを間借り。
まず、Django をインストールるするには、 pip からDjangoをダウンロードするので、先にpipをインストールします。
Flaskと同様に pip からダウンロードするので、Flaskがインストール済みなら、pipも入っているハズです。
そして、Linux の場合、
sudo pip install django
でdjangoをインストールできます。
pipのインストール方法および使い方は、ググってください。
なお、Djangoのバージョン確認の方法は
python -m django --version
です。
使い方[編集]
Django を使うには、コマンドラインを使う必要があります。
まず、プロジェクトのフォルダ群を作らないといけないのですが、さすがにこれは自動生成してくれるコマンドがあります。
コマンド
django-admin startproject プロジェクト名
で、まずプロジェクトを作ります。
上記コマンドを使えば、Django用のプロジェクトのフォルダを自動生成してくれます。
たとえば、 「projtest」というプロジェクトを作るなら
django-admin startproject projtest
になるわけです。
そして、このプロジェクト内でこれから作業するので、移動コマンドcdを使い、
cd プロジェクト
で、さきほど作成したプロジェクトのフォルダ内に移動します。
コマンド
python manage.py runserver
を使うと、Django の webサーバーが立ち上がります。
webブラウザで、
http://127.0.0.1:8000/
でアクセスできます。
まだ何もユーザー側でHTMLを作っていないので、初期設定のHTMLページが表示されるので、表示ページには英文およびロゴマークでロケットの打ち上げ絵が書かれています。水色っぽいロケットの打ち上がってるイラストが出たら、とりあえず、ここまでの作業は成功です。
サーバ立ち上げのコマンドの冒頭は、 django-admin
ではなく python
ですので、間違えないようにしましょう。なんでここだけpythonなのか謎ですが、そういう仕様なので、従うしかありません。
なお、自動作成ずみのプロジェクト用フォルダ内にすでに manage.py というスクリプトがあり、それを上記コマンド python manage.py runserver
で実行している仕組みです。
なお、サーバを終了するには、Ctrlキー + Cキー の同時押しです。(Flaskと同じ終了コマンド)
次回以降のサーバの立ち上げは
cd プロジェクト名 python manage.py runserver
になります。
自作HTMLページの立ち上げ[編集]
では、これからホームページを作りましょう。Djangoではホームページは「アプリ」に分類されるので、コマンド
python manage.py startapp アプリ名
で、まずDjangoアプリを作ります。
このコマンドを実行する場所は、どこでもいいのですが、プロジェクト内でしたほうがラクなので、中で作成した場合、コマンドライン画面は
[ユーザ名@localhost プロジェクト名]$ python manage.py startapp アプリ名
のようになります。
今回、最終的に作りたいのはホームページなので、たとえば「hptest」というアプリ名を作ったとしましょう。
Django用フォルダ内に自動作成されたアプリ名フォルダの中に
- views.py
from django.shortcuts import render # Create your views here.
というファイル名と上記のコード内容のファイルがありますので、それをマウスで右クリックして、普通に開き、これから編集することで、ホームページ作成する仕組みです。
これを編集し、下記のような関数を付け足します。関数名(func)とその引数(arg)は自由に設定できますが、「render」はそのままにしてください。
- views.py 変更後
from django.shortcuts import render # Create your views here. def func(arg): return render(arg, 'testpage.html')
書式はもちろん
def 関数名(引数名):
return render(引数名, 'ウェブページの名前.html')
です。
次に、プロジェクト名と同名のフォルダが、プロジェクトに入った階層にあるので、その同名フォルダに、マウスで移動します。
そして、その同名フォルダ内に、urls.py というファイルが存在し、↓のほうに、下記のようなコードが書かれています。
- プロジェクト側 urls.py の抜粋
from django.contrib import admin
from django.urls import path
urlpatterns = [
path('admin/', admin.site.urls),
]
このファイルのこのコード部分を下記のように書き換えます。
from django.contrib import admin
from django.urls import path, include # 追加せよ include を
urlpatterns = [
path('admin/', admin.site.urls),
path('アプリ名/', include('アプリ名.urls') ) # 追加
# たとえば path('hptest/', include('hptest.urls') )
]
次に、アプリ側に、urls.py という同名のファイルを作りますが(初期設定では用意されてないので、ファイルを新規作成してください)、中身は別です。下記のようなコードをアプリ側に書きます。
- アプリ側 urls.py の抜粋
from django.urls import path
from . import views
urlpatterns = [
path('templates/', views.func, name='func'),
]
そして、さらに、「templates」フォルダを作り、そこに最終的に表示したいHTMLを入れます。このフォルダ名は、必ず「templates」でないといけません。(アプリ側 urls.py のコード中のpath('templates/',
といっしょに別フォルダ名に書き換えて違うフォルダ名にしても、エラーになります。なので、必ず「templates」というファイル名にしてください。)
path('templates/', views.func, name='func'),
の第一引数の部分は、webブラウザなどで「templates」のメッセージが送られた場合に、テンプレートフォルダにあるファイルで対応する事を言っています。
なので、たとえば、第一引数を別名にして
path('tbetumei/', views.func, name='func'),
のようにしても、webブラウザでのアクセス時にURL欄に
http://localhost:8000/hptest/betumei/
と入力すると、ブラウザからtemplatesフォルダ内のHTMLなどにアクセスできてしまいます。ですが、まぎらわしいので、第一引数は「templates」のままに、しておいてください。
このtemplatesフォルダに入れるHTMLには、とりあえず、
<h2>Hello Django World!</h2>
と書いてあるとしましょう。
さらに、プロジェクト側にある setting.py に、INSTALLED_APPS という項目があり、最初は
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
]
と書かれていますが、これに私達の作成するアプリ名をつけたすことで、そのアプリが追加されたことを知らせます。
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'アプリ名', # たとえば 'hptest',
]
あとは、サーバを立ち上げて、webブラウザで
http://localhost:8000/アプリ名/templates/
にアクセスすれば、HTMLファイルの内容が表示されます。(上述のコード例の場合なら、 http://localhost:8000/hptest/templates/ にアクセスする事になります。 )
- 表示結果
大きな文字で
Hello Django World!
と表示されれば成功です。
ログインページの作成など[編集]
Django では、ログインページそのものを自動作成する機能もあり Auth といいますが、設定が必要です。
これとは別に、ログインページでよく使いそうな、Eメールアドレス入力フォームや、会員サイトでの入会時の生年月日の登録などで使いそうな年月日入力フォームなど、各種の入力フォームを、テンプレートで自動作成する機能があり、Formクラスと言います。
Eメール入力フォームなら、メールアドレス形式以外の文字列が入力されても、送信を禁止します。このように、入力内容を自動的に検査することを「バリデーション」といいます。Formクラスを使うと、バリデーションの機能を使えます。
また、その他の一般のDjangoの入力フォームでも、入力時の必須項目などを設定できます。たとえば、登録ページでユーザー名が未入力なのに「送信」ボタンの押された場合には、「この項目を入力してください」のような警告メッセージを、webページ上で出させて、送信させないでユーザーに再入力させる事ができます。
Djangoなどのフルスタックwebフレームワークを使う利点として、サーバー製作者は上述のように、入力欄のチェック機能を自作する手間が省けます。
複数ページの作成[編集]
いきなりログインページを作っても、複雑で理解が浅くなってしまうので、まずは、リンクで結ばれている複数のHTMLページをアップロードする方法を学びましょう。
templates にHTMLファイルが2つあるとして、
- testpage.html
- testpage2.html
というファイルがあるとしましょう。
まず、これをアップロードするために、コードを下記のように書き換えます。
- アプリ側 urls.py
</syntaxhfrom django.urls import path
from . import views
urlpatterns = [
path("testpage.html", views.func, name="func"),
path("testpage2.html", views.func2, name="func2"),
]
なお、(アプリ側でなく)プロジェクト側 urls.py の抜粋はそのままにしておきます。
さて、views.pyに、2ページ目のHTMLのための関数を追加する必要があります。
- views.py
from django.shortcuts import render
# Create your views here.
def func(arg):
return render(arg, "testpage.html")
def func2(arg):
return render(arg, "testpage2.html")
そして、それぞれのHTMLファイルには
- testpage.html
<a href="http://localhost:8000/hptest/testpage2.html">他ページにワープ</a> <br>
- testpage.html
ここは2ページ目です。
と書いてあるとしましょう。
説明の簡単化のため、まだ、各種の Django テンプレートは使わないでおきましょう。
これだけすれば、とりあえず、webブラウザで、
http://localhost:8000/hptest/testpage.html
にアクセスすれば、1ページ目を表示できます。
そして、ブラウザに表示されたリンク文をクリックすれば、2ページ目に移動できます。
2ページ目に移動したとき、アドレス欄の末尾が、きちんと2ページ目のファイルである testpage2 に変わっている事を確認しましょう。つまり、
http://localhost:8000/hptest/testpage2.html
というふうに、なっているハズです。
とりあえず、これで読者のアナタは、Djangoに複数のHTMLページをアップロードする事ができました。
では、今度はHTMLファイルのリンクを、Djangoテンプレートタグの一種である URLテンプレートタグ を使って書き換える方法を学びましょう。
単に、1ページ目のhrefタグの引数を、下記のようにurlテンプレートタグを使って書き換えるだけです。なお、前回との表示の区別のため、下記コードでは表示される文章を少々、追加してあります。
- testpage.html
<a href="{% url "func2" %}">他ページにワープ. なお文章を書き換えてある。</a> <br>
参考のため、2ページ目のHTMLも再掲しておきます。
- testpage.html
ここは2ページ目です。書き換え後のワープ。
あとはもう、
http://localhost:8000/hptest/testpage.html
にアクセスすれば、前回と同様のアクセス結果になります。
- ^ “Jinja — Jinja Documentation (3.0.x)” (2021年11月28日). 2021年11月29日閲覧。