Pythonだけどweb開発したい! ~99%Pythonだけでwebアプリを作る~
この記事はPython Advent Calender 2021 16日目の記事です。(タイトルまちがったので上げ直しました。)
今年のアドカレももう折り返しですね。今年は調子に乗って参加しすぎてぶっ倒れそうですが、今年の頑張って作ったアプリのうち1つを公開します。
GitHub
全体
フロントエンドだけGitHub Pagesでデプロイした版(動作を見れます)
リポジトリ: https://github.com/bluepost59/brython_todo
はじめに
「Pythonしか書けないけどイケてるwebアプリ開発したい!」そう思ったことはありませんか?
webアプリ開発には、webサーバのコードとブラウザサイドのコードを開発する必要があります。特に後者はJavaScriptが必須であり、Pythonと違う記法やcallbackのようなJavaScript独特の概念を理解する必要があり、なかなか難しそうです。
そんなPythonistaの皆さんの夢をかなえるべく、今回はタイトルの通り99% Pythonだけで、webアプリ入門の定番であるToDoリストを作ってみます。
バックエンド: Flask
バックエンドにはPython使いにはおなじみのFlaskを使います。
せっかくなのでwebアプリらしくサーバサイドともAjax通信してサーバにデータを蓄積するようにします。初期画面はFlaskでロードしてタスクが登録されたらDBに保存するようにします。DBはサーバ立てるのが面倒なのでSQLiteを使います。
htmlなどをホストするAPIのほかにajax通信を受けるAPIを開けておきます。今回はSQLiteにタスクを格納するAPIを開けておき、登録時だけDBに保存するようにします。DBのタスクはビューを描画するときにテンプレートに埋め込む形にします。SQLiteはサーバを立てなくてよいので便利です。
import json
from flask import Flask,Request
app = Flask(__name__)
# ビューの作成
@app.route("/")
def serve_route():
# データベースからデータを引っ張ってくる
conn = sqlite3.connect("todo.db")
cursor = conn.cursor()
cursor.execute("select title from todo")
raw_tasks = cursor.fetchall()
tasks = [mytask[0] for mytask in raw_tasks]
# HTMLにtasksの内容を埋め込み、レスポンスを返す
return render_template("main.html", tasks=tasks)
jinja2のtemplate
FlaskではJinja2というテンプレートエンジンでレンダリングします。今回のToDoリストのように可変長なものでも、forループをテンプレートの中に埋め込むことでうまく表現することができます。
<div id="tasks_area" class="tasks_container">
{% for mytask in tasks%}
<div class="task">
<input type="checkbox"></input>
<div>{{ mytask }}</div>
</div>
{% endfor %}
</div>
フロントエンド: Brython
フロントエンドはBrythonを使います。あまり聞きなじみのないものかも知れませんが、実はこのライブラリは結構イケていて、JavaScriptだとjqueryなどのライブラリを使って実装するajax通信[1]もPythonの標準的な記法で記述できます。
Brythonは文法はPythonですが、.bry
という拡張子で保存することが推奨されています。特にFlaskの場合だとPythonコードは全部サーバコードと認識するので、拡張子が.py
だとブラウザ側のコードを編集してもサーバが止まってしまいます。
ただし、はまりどころがあります。JSONをサーバに送るときjson.dumps
して文字列として送らないとgetのクエリのような形式で送られてしまい、サーバ側でパースエラーになります。
def add_task(task_name: str):
# POSTする
ajax.post(
url="http://localhost:3000/register/",
headers={"Content-Type": "application/json", },
data=json.dumps({"title": task_name, "detail": "detail"})
)
# DOM操作
new_task_checkbox = browser.document.createElement("input")
new_task_checkbox.type = "checkbox"
new_task_name = browser.document.createElement("div")
new_task_name.text = task_name
new_task = browser.document.createElement("div")
new_task.class_name = "task"
new_task.appendChild(new_task_checkbox)
new_task.appendChild(new_task_name)
browser.document["tasks_area"].appendChild(new_task)
# 登録ボタン
@browser.bind(browser.document["new_task_register"], "click")
def register_new_task(ev):
add_task(browser.document["new_task_input"].value)
BrythonはPythonコードをJSにトランスパイルして実行しています。そういう意味で「99%」とつけました。というかPython以外にもhtmlとCSSは手書きしないといけません。ここはブラウザで動かす以上仕方がないです...。
最後に
JavaScriptもできるエンジニア青ポス「JavaScriptでええやん」
とはいえ、JavaScriptは初学者にはとても難しい言語だと思います。言語仕様に加えて非同期実行やwebの通信の仕組みも同時並行で学ばないといけないので、DOMを読ませるにしても工夫が必要だったりします(head部分に書いたscriptでdocument.getElementById()するとNullが返るとか...)。
その点Brythonでは非同期実行が必須ではないので、ajaxによる非同期通信も普通のPythonコードのように書くことができます。実用としてはともかく、Pythonしかできない初心者プログラマがwebに入門するにはとてもわかりやすいのではないでしょうか。
ちなみに(宣伝)
次回はWEBやデータ分析に関する投稿をみんなでしてみよう Advent Calendar 2021で、もっとヤバいPython実行環境を解説します[2]。お楽しみに。
Discussion