狠狠撸

狠狠撸Share a Scribd company logo
1
Bottleではじめる
WEBアプリの最初の一歩
2016/07/06
みんなのPython勉強会#14
山田 聡(@denzowill)
2
# whoami
?名前
? 山田 聡(@denzowill)
?仕事
? DBエンジニア(○racle,PostgreSQL)
? チョットだけWebLogicエンジニア
? Pythonは趣味
?スキル
? 統計もわかりません
? 機械学習もわかりません
? ちょっとWEBアプリわかります
3
アジェンダ
?WEBアプリ?
?フレームワークとハードル
?だからBottle
4
アジェンダ
?WEBアプリ?
?フレームワークとハードル
?だからBottle
5
WEBアプリ?
?そもとも普通のWEBサーバ
Apacheとか、WEBサーバは指定されたアドレスにある
静的なHTMLをそのまま戻す。内容は固定。
6
WEBアプリ?
?昔からのWEBアプリケーション
サーバでJavaとかPythonが動いてて、HTTP通信で
渡ってきたデータを元に、頑張って動的なHTMLを
組み立てて、ブラウザでそれを表示する。
7
WEBアプリ?
?最近のWEBアプリケーション
動的なHTMLを受けとるだけでなく、Javascriptが頑
張って裏ですっごい非同期通信して、ページ遷移無しで
もいろいろ画面がかわる
8
今回は?
9
今回は?
今回はこちら中心です。
(基本なので。)
10
WEBアプリに必要なもの
ルーティング
http://xx/list
http://xx/add
http://xx/del/2
入口
view_list()
add_item()
del_item(
id=2
)
→ URLと処理のマッピング
11
WEBアプリに必要なもの
ビジネスロジック → あなたがやりたいこと
普通の処理
def view_list():
connect = db.connect()
cur = connect.cursor()
cur.execute("select id,name from items order by id")
item_list = []
for row in cur.fetchall():
item_list.append({
"id":row[0], "item_name": row[1]
})
return item_list
DBから商品一覧を
取得したい etc
12
WEBアプリに必要なもの
HTMLの表示 → ビジネスロジックの結果を画面に
<h1>アイテム一覧</h1>
<table border="1">
%for item in item_list:
<tr>
<td>{{item.id}}</td>
<td>{{item.name}}</td>
</tr>
%end
</table>
13
アジェンダ
?WEBアプリ?
?フレームワークとハードル
?だからBottle
14
フレームワークとハードル
?WEBアプリケーションフレームワーク(WAF)?
あるルールに従って作成すると、簡単にWEBアプリケー
ションが作成できるようにしたライブラリの集合のよう
なもの。
15
フレームワークのよくある機能
?ルーティング
? URLに応じて処理先を割り当て
?テンプレート
? HTMLを簡単に動的に組み立て
?ORM
? 搁顿叠惭厂等をオブジェクトとして透过的に操作
16
フレームワークのよくある機能
?ルーティング
? URLに応じて処理先を割り当て
?テンプレート
? HTMLを簡単に動的に組み立て
?ORM
? 搁顿叠惭厂等をオブジェクトとして透过的に操作
フレームワークによっては
他のORMライブラリを
組み込むケースも
17
WEBアプリのデザインパターン
MODEL
VIEW
CONTROLER
ビジネスロジック
DBでの永続化
画面表示
HTML/CSS
ルーティング
MVの橋渡し
18
WEBアプリのデザインパターン
MODEL
VIEW
CONTROLER
19
WEBアプリのデザインパターン
MODEL
VIEW
CONTROLER
→ こうするとキレイに書けるよって話
20
このあたりから
途端に辛い
21
なんでつらい?
?MVCとかMTVとかいろいろある
?フレームワーク毎に解釈が違ったりする
?フレームワークの作法に従えばなんとなくは
できる
?でも、それはそのフレームワークに縛られる
22
なんでつらい?
?MVCとかMTVとかいろいろある
?フレームワーク毎に解釈が違ったりする
?フレームワークの作法に従えばなんとなくは
できる
?でも、それはそのフレームワークに縛られる
一旦MVCは忘れて
基本を見てみる
23
機能と学習量の関係
すごい
つらい
24
機能と挫折率の関係
すごい
つらい
25
機能と挫折率の関係
すごい
つらい
26
アジェンダ
?WEBアプリ?
?フレームワークとハードル
?だからBottle
27
Bottleはとてもシンプル
28
Bottleはとてもシンプル
?テンプレート、ルーティングの機能あり(ORM無し)
?bottle.pyという1ファイルがすべて
?外部ライブラリに依存性無し
?シンプルだからWEBアプリの動きをつかみやすい
学習に最適!
29
この時点で残り10分
ですが(想定)、いまから
アプリ書きます
30
つくるもの
?アイテムの一覧が見られる(参照)
?フォームからアイテムを追加できる(登録)
?既存のアイテムを削除できる(更新)
この3つが大体基本
31
Bottleセットアップ
$ mkdir <適当なディレクトリ>
$ cd <作ったディレクトリ>
$ wget https://github.com/bottlepy/bottle/raw/master/bottle.py
bottle.pyを持ってくれば終わり
32
Bottleの動作確認
from bottle import route, run
# / にアクセスしたら index関数が呼ばれる
@route("/")
def index():
# 画面に表示されて欲しいHTMLを戻す
return "<h1>WELCOME STAPY!</h1>"
# サーバを起動(localhost:9999で起動する設定)
run(reloader=True, port=9999)
app.py
33
$ python app.py
34
アイテム一覧見たい
# アイテム一覧を戻す関数
@route("/list")
def view_list():
# ダミーデータ(あとでDBから取得するようにする)
item_list = [
{"id": 1, "name": "りんご"},
{"id": 2, "name": "ばなな"},
{"id": 3, "name": "すいか"},
]
# 表示用のHTMLを組み立てる
display_html = "<table border='1'>"
for item in item_list:
display_html += "<tr>"
display_html += "<td>{}</td>".format(item["id"])
display_html += "<td>{}</td>".format(item["name"])
display_html += "</tr>"
display_html += "</table>"
return display_html
app.py
35
http://127.0.0.1:9999/list
36
HTMLをベタがき
つらいので
テンプレートつかう
37
テンプレート使う
<h1>アイテム一覧</h1>
<table border="1">
%for item in item_list:
<tr>
<td>{{item["id"]}}</td>
<td>{{item["name"]}}</td>
</tr>
%end
</table>
list_tmpl.tpl
ほぼHTML
% や{{ }}のなかだけ
Pythonのように処理される
item_listは
使うときにapp.pyから
ディクショナリを渡す
38
テンプレート使う
from bottle import route, run, template
:
:
# アイテム一覧を戻す関数
@route("/list")
def view_list():
# ダミーデータ(あとでDBから取得するようにする)
item_list = [
{"id": 1, "name": "りんご"},
{"id": 2, "name": "ばなな"},
{"id": 3, "name": "すいか"},
]
# 表示はテンプレートを戻すだけ
return template("list_tmpl", item_list=item_list)
app.py
39
http://127.0.0.1:9999/list
さっきと同じだけど\(^o^)/
40
DBのデータを参照する
(sqliteつかう)
41
初期データの準備
import sqlite3
# items.dbとつなぐ(なければ作られる)
conn = sqlite3.connect('items.db')
c = conn.cursor()
# テーブル作成
c.execute("create table items(id, name)")
# 3行投入
c.execute("insert into items values(1,'りんご')")
c.execute("insert into items values(2,'ばなな')")
c.execute("insert into items values(3,'すいか')")
# 確定
conn.commit()
# バイバイ
conn.close()
pythonを対話型で起動して実行
42
DBからitem_listを取得するように変更
import sqlite3
from bottle import route, run, template
:
:
@route("/list")
def view_list():
# items.dbとつなぐ
conn = sqlite3.connect('items.db')
c = conn.cursor()
c.execute("select id,name from items order by id")
item_list = []
for row in c.fetchall():
item_list.append({
"id": row[0],
"name": row[1]
})
conn.close()
# 表示はテンプレートを戻すだけ
return template("list_tmpl", item_list=item_list)
app.py
43
登録処理作る
44
登録用のフォームのテンプレート作る
<h1>アイテム登録</h1>
<form action='' method='POST'>
<input type='text' name='item_name' placeholder='アイテム名'/>
<input type='submit' value='登録' />
</form>
add_tmpl.tpl
45
ルーティングとメソッド作成
@route("/add", method=["GET","POST"])
def add_item():
return template("add_tmpl")
app.py GETとPOST
両方でアクセス
できるようにする
46
http://127.0.0.1:9999/add
登録は押せる
ただし何も起きない
47
ルーティングとメソッド作成
@route("/add", method=["GET","POST"])
def add_item():
if request.method == "POST":
# POSTアクセスならDBに登録する
# フォームから入力されたアイテム名の取得(Python2ならrequest.POST.getunicodeを使う)
item_name = request.POST.getunicode("item_name")
conn = sqlite3.connect('items.db')
c = conn.cursor()
# 現在の最大ID取得(fetchoneの戻り値はタプル)
new_id = c.execute("select max(id) + 1 from items").fetchone()[0]
c.execute("insert into items values(?,?)", (new_id, item_name))
conn.commit()
conn.close()
return "SUCCESS"
else:
# GETアクセスならフォーム表示
return template("add_tmpl")
app.py
POST/GETで分岐
GETはフォーム出すだけ
formからPOSTされた
データを取得
48
http://127.0.0.1:9999/add
49
削除処理作る
50
一覧画面のテンプレート変更し削除リンク追加
<h1>アイテム一覧</h1>
<a href='/add' >新規作成</a>
<table border="1">
%for item in item_list:
<tr>
<td>{{item["id"]}}</td>
<td>{{item["name"]}}</td>
<td><a href="/del/{{item['id']}}">削除</a></td>
</tr>
%end
</table>
list_tmpl.tpl
ついでに新規作成つけとく
削除リンク
/del/1や/del/2といった
URLへリンクする
51
削除処理を追加、URLから削除対象のID取得
# /del/100 -> item_id = 100
# /del/one -> HTTPError 404
@route("/del/<item_id:int>")
def del_item(item_id):
conn = sqlite3.connect('items.db')
c = conn.cursor()
# 指定されたitem_idを元にDBデータを削除
c.execute("delete from items where id=?", (item_id,))
conn.commit()
conn.close()
# 処理終了後に一覧画面に戻す
return redirect("/list")
app.py
delの後ろに数字がくると
関数の引数として取れる
後はそれで
delete文するだけ
52
http://127.0.0.1:9999/list
押したら消える
53
完成https://github.com/denzow/sample_bottle
54
10分で基本的な要素を
抑えたWEBアプリが
できました(想定では)
55
次の一歩に向けて
?参照?登録?削除ができればアプリは作れる
?見た目はCSSやJavascriptを覚える
? 参考:Bootstrap http://getbootstrap.com/
?アプリが大きくなると各所で辛さが出る
? SQLの管理
? ルーティングの管理
?辛くなったらもっと高機能なWAFを覚えて見る
56
ご清聴ありがとうございました。

More Related Content

产辞迟迟濒别で始める奥贰叠アプリの最初の一歩