今、話題の人工知能(AI)などで人気のPython。初心者に優しいとか言われていますが、全然優しくない! という事を、つらつら、愚痴っていきます

267.ラズパイ無双[13_bottle vs flask]

»

初回:2022/7/27

 Raspberry Pi (ラズベリーパイ、通称"ラズパイ")で何か作ってみようという新シリーズです。カメラ画像をストリーミング出来るサーバーを、bottleベースで作りましたが、flask版も用意しておこうと思います。

P子「bottle信者だと思ってたわ」※1

 前提として、ラズパイで簡易的なWebAPIサーバーを使うのであれば、bottleで十分、いや、bottle 一択だという思いは持っていますが、Django ほど大規模な仕組みは必要ないけど、それなりにきちんとしたシステムを作りたいと思っている場合は、flask を使いたいという要望も多いと思います。

 ただし、flask については全くの素人ですし、bottleについては、触り始めた程度なので、記述方法や対応方法が間違っているかもしれませんので、そこは各自で調査してください。

P子「読者丸投げね」

 まあ、書籍化でも決まれば、きちんと調査しますけど...

P子「まず、ありえない話ね」

【目次】

1.ソース

 まずは、今回の bottle と flask のソースを、例の作業部屋に置いておきます。

 ≪OSDN の作業部屋≫
  https://ja.osdn.net/users/chatrun/pf/eu63/files/

 OSDN の作業部屋という所に、@IT を作成しました。この中の No267.zip にソースを置いています。
 wwwb というのが、bottle 用の環境で、このフォルダに、別にダウンロードしてきた bottle と、waitress をインストールします。
 wwwf は、flask 用の環境で、flaskは通常の pipでのインストール、waitress は、インストールでも、bottle と同じく、フォルダ内に作成しても構いません。

 フォルダ構成の違いというと、wwwb のテンプレートフォルダは、views で、wwwf のテンプレートフォルダは、templates です。ソースにコメントを書いていますが、それぞれ、テンプレートフォルダ名を変更する機能を持っていますので、無理やり同じフォルダに構築することも可能でしょう。

 ただ、前回も書いたように、bottle派もflask派も互換運用は求めていないと思いますので、基本は変えずに差分の説明をしたいと思います。

2.サーバー部分の差分

 ogServer.py の差分の説明です。

No 行番号 bottle flask
18,19 import bottle import flask
25,26 def enc( key ) 定義 なし
63,67 app = bottle.Bottle() app = flask.Flask(__name__)
84,85 if subapp : app.merge(subapp) if subapp : app.register_blueprint(subapp)
108,109 url = bottle.request.params.get( "action",name ) url = flask.request.args.get( "action",name )
121,122 prmDicにparamsセット なし
124,125 params = dict( { "title":TITLE ,"enc":enc } , **modules, **prmDic ) params = dict( { "title":TITLE } , **flask.request.args , **prmDic )
127,128 return bottle.template(url,params) return flask.render_template(url,params=params,**modules)
132,139 static ルーティング処理 なし
155,159 bottle.response.content_type = 'multipart/x-mixed-replace;boundary=frame'
return gen(cam,argp.skip)
return flask.Response(gen(cam,argp.skip),
mimetype='multipart/x-mixed-replace; boundary=frame')
169,172 bottle.response.content_type = 'image/jpeg'
return cam.get_frame()
return flask.Response(cam.get_frame() , mimetype='image/jpeg')

 ① flask の import は、

 from flask import Flask , request , render_template , Response

 というのが、普通でしょう。今回は、bottle との差分が判りやすい様に、flask を個々に付けています。

 ② def enc の箇所は、bottle で日本語パラメータを使用する場合のUTF-8 変換ロジックです。flaskでは、どうするのか分からなかったので、今回は未対応です。

 ③ app オブジェクトの生成箇所です。テンプレートフォルダを変更する場合の方法は異なります。

 ④ subapp としてルーティングをモジュールで実行する場合の組み込み方法については、bottle は、merge を使用しており、flaskは、register_blueprint を使用しています。

 ≪参考資料≫
  https://doitu.info/blog/5ac362762e280f0095116f10
  Bottleでファイルを分割する方法

 ≪参考資料≫
  https://rurukblog.com/post/Flask-blueprint/
  【Flask】blueprintの使い方

 ⑤ requestパラメータからの値取得は、bottle はparams.getメソッド、flask は、args.getメソッドを使用します。

 ⑥ テンプレートに辞書を渡す方法は、少し異なります。実はこのあたりはよく分かっていませんので、もしかすると、もっと効率的な方法があるのかもしれません。

 ⑦ パラメータの生成方法です。

 ⑧ テンプレートの適用方法です。

 ⑨ static ルーティング処理については、flask ではルーティングの記述が不要です。

 ⑩ content_typeの返し方と、ストリームのgen関数の返し方が異なります。

 ⑪ snapshot ルーティング処理も、⑩と同様です。

3.フィルター部分の差分

 フィルター部分の差分の解説の前に、差分のないプログラム部分を説明しておきます。
 camera.py
 test_module.py

 については、bottle と flask で共通です。test_module.py については、インスタンス化して、ogServer.py に渡して、辞書にセットして、テンプレートに渡すだけなので、共通化できます。フィルターについても、実際はインスタンスをogServer.py に渡して、camera.py に渡すだけなので、共通化できます。

 共通化できていないのは、サブアプリで、これは bottle や flask のルーティングとモジュール組み込みに関連しているため、差分が出来ます。そして、実際にはフィルターやモジュールは、Web画面からの値の受け取りや受け渡しを行うため、それぞれに特化した方法になりますが、def new_obj() という関数内だけにとどめています。

 test_filter.py が、差分のあるファイルで、new_obj 関数内だけが異なります。

 今回、あえて関数内で import していますが、単に差分を判りやすくしただけです。実際に bottle や flask を使用る場合は、先頭にmport するでしょう。ここでも、import flask としていますが、from flask import Blueprint , request と記述していて構いません。

 微妙な注意点としては、ルーティング部分で、bottle は method='POST' と文字列で、flask は methods=['POST'] とリストで記述します。

 最後に、JSON形式のリクエストの受け取り方が少し異なります。この辺は、flask の方がシンプルな気がします。

4.テンプレート部分の差分

 まず、デフォルトのテンプレートフォルダ名が異なります。bottle は、views で、flask は、templates となっています。すでに、ogServer.py のソースにコメントしているように、bottle でテンプレートフォルダを変える場合は、

 bottle.TEMPLATE_PATH += ['./templates'] # views → templates

 と記述し、flask でテンプレートフォルダ名を変える場合は、

 app = flask.Flask(__name__, template_folder="views") # templates → views

 と記述します。

 ① 変数名の参照
 header.html の {{title}} の記述は、bottle も flask も共通で、オブジェクトを画面に書き込む(=変数の参照)場合、{{ 変数名 }} の記号を使用します。

 ② 制御文
 index.html で、header.html を include していますが、これは制御文を使用しています。
 bottle では、<% 制御文 %> と記述し、flask では、{% 制御文 %} と記述します。

 bottle は、<% include( "header.html" ) %>
 flask は、{% include( "header.html" ) %}

 となります。

 ③ 変数の代入(制御文)
 test.html で変数の代入を行っていますが、これも、bottle と flask で少し異なります。

 bottle は、<% obj = modname %>
 flask は、{% set obj = modname %}

 のように、flask では、set という記号を付ける必要があります。

 ④、⑤ if や for などのブロック処理(制御文)
 test.html で辞書をループさせて中身を取り出していますが、通常ブロック処理は、python特有のインデントを使ったブロック定義が使えません。そのため、終了条件を記述する必要があります。bottle では、for や if でも、<% end %> を使用し、flask では、{% endfor %} や {% endif %} と記述します。

 bottle
  <% for k,v in obj.empData.items() : %>
    {{k}}{{v}}
  <% end %>

 flask
  {% for k,v in obj.empData.items() : %}
    {{k}}{{v}}
  {% endfor %}

 bottle では、<% と %> で囲えば、制御ブロックとして記述でき、先頭が % で始めれば制御文として評価されます。個人的には、% 一文字での記述は簡易的ですが、例え1行でも、<% と %> で囲って、制御文であることが一目でわかる方が好みです。

5.まとめ

 bottle と flask は、ほとんど同じように使えると思います。後は好みの問題だと思います。もちろん、機能的には、flask に軍配が上がるかもしれませんが、逆に複雑にしたくない場合は、bottle が良いと思います。

 bottle に、SQLiteというデータベースを使用すれば、結構本格的なWebアプリも作れます。ラズパイ上に簡易システムを構築する場合、bottle で十分でしょう。

 今後は、bottle 中心にソースを書いていきますが、flask派の方も、ほんの少しの修正で適用できますので、ぜひ、お楽しみにしていてください。

ほな、さいなら

======= <<注釈>>=======

※1 P子「bottle信者だと思ってたわ」
 P子とは、私があこがれているツンデレPythonの仮想女性の心の声です。

Comment(0)

コメント

コメントを投稿する