(v_15)PythonのフレームワークBottleを試す(1)
Bottleで始めるWEBアプリ
Pythonで使えるWebフレームワークのBottleを少し学習してみました。
何かに使ってみようと思いましたが思い浮かびませんでしたので、「bottleで始めるWEBアプリの最初の一歩「https://www.slideshare.net/satoshiyamada71697/bottleweb」を参考に試してみました。
具体的には、名前と年齢のデータベースをブラウザで以下のように名前と年齢のデータ一覧を表示、新規登録、「変更、削除」の操作ができる感じにしました。
データベースも扱うのでsqlite3も使っています。
SQL文の書き方は「https://www.sejuku.net/blog/104588」を参考にしました。
データベース
名前と年齢のデータベースitems.dbをsqlite3を使って作成します。
Thonnyのshellで確認しながら進めます。
#sqlite3をインポート
>>> import sqlite3
#データベースitems.dbを接続します。無ければ作成される
>>> con=sqlite3.connect('items.db')
>>> type(con)
<class 'sqlite3.Connection'>
#データベース操作のためCursorオブジェクトを作成
>>> cur=con.cursor()
>>> type(cur)
<class 'sqlite3.Cursor'>
#カラム id,name,ageのテーブルを作成
>>> sql='CREATE TABLE items(id,name,age)'
>>> cur.execute(sql)
<sqlite3.Cursor object at 0x03C64D20>
#SQL文 INSERT INTO~VALUES~でテーブルにデータ追加
>>> sql="INSERT INTO items VALUES (1,'yamada',30)"
>>> cur.execute(sql)
<sqlite3.Cursor object at 0x03C64D20>
#SQL文 SELECT~FROM~でテーブルからデータ取り出し、fetchallで表示
>>> b=cur.execute("SELECT * FROM items")
>>> b.fetchall()
[(1, 'yamada', 30)]
#executemanyを使ってテーブルに複数行のデータ追加する
>>> data=[
(2, 'sato',22),
(3, 'kawano',33),
]
>>> sql="INSERT INTO items VALUES (?, ?, ?)"
>>> cur.executemany(sql,data)
<sqlite3.Cursor object at 0x03C64D20>
>>> b=cur.execute("SELECT * FROM items")
>>> b.fetchall()
[(1, 'yamada', 30), (2, 'sato', 22), (3, 'kawano', 33)]
#確定する
>>> con.commit()
#接続を閉じる
>>> con.close()
以上を整理してまとめています。
web_sql_01b.py
!/usr/bin/env python3
# -*- coding: utf-8 -*-
import sqlite3
#sqlite3.Connection
con=sqlite3.connect('items.db')
#sqlite3.Connection
cur=con.cursor()
#table
cur.execute('CREATE TABLE items(id,name,age)')
data = [
(1, 'yamada',30),
(2, 'sato',22),
(3, 'kawano',33),
]
#executemany テーブルに複数行のデータ追加(レコード登録)を行う
cur.executemany("INSERT INTO items VALUES(?, ?, ?)", data)
# 確定
con.commit()
#全カラムデータを選択
b=cur.execute("SELECT * FROM items")
#データ表示
print(b.fetchall())
con.close()
実行結果
>>> %Run web_sql_01b.py
[(1, 'yamada', 30), (2, 'sato', 22), (3, 'kawano', 33)]
データ表示 /list
「http://localhost:8080/list」でデータリスト表示されるようにします。
その前に、HTMLのテンプレートファイルを使って「http://localhost:8080/temp」で以下が表示されるようにしてみます。
以下のテンプレートファイル「temp_01.tpl」を作成してワークフォルダーに保存します。
temp_01.tpl
<!DOCTYPE html>
<html>
<h3 style="color:red;">Python Bottle SQLite3</h3>
<p style="color:blue;">テンプレートのテスト</p>
</html>
</code></pre>
Thonnyのshellで確認しながら進めます。
#bottle.pyからroute, run, templateをimport
>>> from bottle import route, run, template
#/tempでテンプレートを表示
>>> @route('/temp')
def test():
return template('temp_01')
#localhostを起動
>>> run(host='localhost', port=8080, debug=True)
Bottle v0.13-dev server starting up (using WSGIRefServer())...
Listening on http://localhost:8080/
Hit Ctrl-C to quit.
C:\****\****\****\bottle.py:4088: DeprecationWarning: Flags not
at the start of the expression '\\{\\{((?:(?mx)( ' (truncated)
patterns = [re.compile(p % pattern_vars) for p in patterns]
127.0.0.1 - - [**/May/2024 16:44:46] "GET / HTTP/1.1" 404 726
127.0.0.1 - - [**/May/2024 16:44:58] "GET /temp HTTP/1.1" 200 146
「http://localhost:8080/temp」で表示されます。
ちなみに「http://127.0.0.1:8080/temp」でもよいです。
「Ctrl-C」で終了します。
Pythonコード埋込
HTML内にPythonコードを記載して処理するには、行を「%」でマークし、「%end」で明示的に閉じます。
HTMLのテンプレートファイル「temp_02.tpl」を以下のようにしました。
今日の日付と/tempで返される値を足し算して結果を表示します。
temp_02.tpl
<!DOCTYPE html>
<html>
<h3 style="color:red;">Python Bottle SQLite3</h3>
<p style="color:blue;">テンプレートのテスト</p>
%import datetime
%today=datetime.date.today()
%d1=data1
%d2=data2
%wa=d1+d2
%end
<p style="color:green;">今日は{{today}}です</p>
<p style="color:brown; Bold;"><strong>{{d1}}+{{d2}}={{wa}}</strong> です</p>
</html>
/tempでtemp_02.tplを表示するように以下のようにしています。
a=10、b=20の値をtemp_02.tplに返しています。
/tempでtemp_02.tplを表示するように以下のようにしています。
a=10、b=20の値をtemp_02.tplに返しています。
test_tmp_02b.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from bottle import route, run, template
@route('/temp')
def test():
a=10
b=20
return template('temp_02',data1=a,data2=b)
run(host='localhost', port=8080, debug=True)
データ表示 /list
「http://localhost:8080/list」でデータリスト表示されるようにします。
テンプレートにlist_tmp3.tplを使っています。
※新規登録、削除、変更も表示されていますが、ここでは関係ないです。
テンプレート list_tmp3.tpl
<!DOCTYPE html>
<html>
<h3>アイテム一覧</h3>
<a href='/add'>新規登録</a>
<table border='1'>
<tr>
<td>id</td>
<td>Name</td>
<td>Age</td>
<td>mod</td>
<td>del</td>
</tr>
%item_list=data
%for item in item_list:
<tr>
<td>{{item['id']}}</td>
<td>{{item['name']}}</td>
<td>{{item['age']}}</td>
<td><a href="/mod/{{item['id']}}">変更</a></td>
<td><a href="/del/{{item['id']}}">削除</a></td>
</tr>
%end
</table>
</html>
部分説明
Pythonコードを埋め込みfor文で各行を繰り返しで表示しています。
スクリプト web_lst_01b.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from bottle import route, run, template
import sqlite3
@route('/list')
def db_list():
con=sqlite3.connect('items.db')
cur=con.cursor()
#ASC 昇順 DESC 降順
c=cur.execute("SELECT * FROM items ORDER BY id ASC")
item_list=[]
for row in c.fetchall():
item_list.append({"id":row[0],"name":row[1],"age":row[2]})
con.close()
# list_tmp3.tpl に渡す引数名 data
return template('list_tmp3',data=item_list)
run(host='localhost', port=8080, debug=True)
部分説明
下方のHTMLのテンプレートファイル list_tmp3.tplを使って表示しています。
SQL文のSELECT~FROM~でテーブルからデータ取り出しする際に
ORDER BY id ASC
を追加してidの昇順で並べ替えています。
ちなみにASCをDESCにすると降順になります。
c.fetchall()で読み出し、以下のようなitem_listリストにしてlist_tmp3.tplに返しています。
先の「items.db」の内容ならitem_listは以下になります。
[{'id': 1, 'name': 'yamada', 'age': 30}, {'id': 2, 'name': 'sato', 'age': 22},
{'id': 3, 'name': 'kawano', 'age': 33}]
実行結果
「http://localhost:8080/list」でデータリストページが表示されました。
新規登録 /add
「http://localhost:8080/add」でデータを追加できるようにします。
Name、Ageの入力にテンプレートにadd_tmp.tplを使っています。
テンプレート add_tmp3.tpl
<!DOCTYPE html>
<html>
<h3>input item name</h3>
<form method='POST'>
<input type='text' name='item_name' placeholder='Name'/>
<input type='text' name='item_age' placeholder='Age'/>
<input type='submit' value='登録'/>
</form>
</html>
スクリプト web_lst_01b.py
#!/usr/bin/env python3
# -*- coding: utf-8 -*-
from bottle import route, run, template, request, redirect
import sqlite3
# /add 新規登録
@route('/add',method=['GET','POST'])
def add_item():
if request.method=='POST':
item_name=request.POST.getunicode('item_name')
item_age=request.POST.getunicode('item_age')
con=sqlite3.connect('items.db')
cur=con.cursor()
#max ID
c=cur.execute('SELECT max(id) FROM items')
max_id=c.fetchone()[0]
new_id=max_id+1
#new_id=cur.execute('SELECT max(id)+1 FROM items').fetchone()[0]
# table が空の場合にid=1を設定する
if new_id==None:
new_id=1
cur.execute('INSERT INTO items VALUES(?,?,?)',(new_id,item_name,item_age))
con.commit()
con.close
return f'SUCCESS id={new_id}, name={item_name}, age={item_age}'
#redirect list-page
#return redirect('/list')
else:
#add-page
return template('add_tmp3')
run(host='localhost', port=8080, debug=True)
部分説明
「http://localhost:8080/add」でelse文の新規登録のページになります。
新規登録のページで名前、年齢を入力、登録ボタンを選択するとmethod==’POST’となり、値がデータベースに追加されます。
SQL文”SELECT max(id) FROM items”でmax(id)の値が得られます。
.fetchone()[0]でmax_id値を得ます。新規登録のnew_idはmax_id+1になります。
‘INSERT INTO items VALUES・・データベースに登録後、return f’SUCCESS id={new_id},・・登録した名前、年齢を表示します。
実使用ではデータ表示ページに戻すので、return redirect(‘/list’)にします。
実行結果
名前をkato、年齢を28で登録した場合です。
データ表示ページで確認すると登録が確認できます。今回はここまでになります。
まとめ
bottlとsqlite3を使って名前と年齢のデータベースからデータの一覧表示ページと新規登録ページを作成できました。次回はデータの削除、変更ページを作成します。