第5章 データベースの基本
1 データベースの基本
データベースを利用するWebサイトを作る前に、db_shouhin.pyにてデータベースの練習を行ってみます。これはweb画面を使わずにコンソールでデータベースの使い方を練習するものです。
今回はSQLiteというpythonにあらかじめ付属するデータベースを使います。VisualStudio CodeにSQLiteのファイルを扱う拡張機能「SQLite3 Editor」をインストールしておきます。コマンドラインで以下から可能です。
code --install-extension yy0931.vscode-sqlite3-editor
もしくはVisualStudio Code画面左の拡張機能のボタンを押して、「SQLite3 Editor」と入力します。
db_shouhin.pyでは、これまでと同様に変数appにFlaskオブジェクトを作成します。
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
次にデータベースを扱う準備をします。ファイル名を指定し、データベースを扱うライブラリ SQLAlchemy のオブジェクト db を作成します。今回は商品や売り上げを管理する販売管理をテーマにし、hanbai.dbというファイルにします。
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///hanbai.db'
db = SQLAlchemy(app)
2 モデルの生成
今回は商品を管理する以下のようなテーブルを作成します。
shouhinテーブル
- 商品ID sid (整数:Integer) 主キー
- 商品名 sname (文字列:String 最大255文字)
- 単価 tanka (整数:Integer)
そのために、商品テーブルのデータを一件入れるためのクラス、Shouhinを作成します。これはSQLAlchemyの「モデル」の作り方に従い作成します。「モデル」とはテーブルの一件のデータを入れる入れ物です。列名を以下のように指定します。
class Shouhin(db.Model):
sid = db.Column(db.Integer, primary_key=True)
sname = db.Column(db.String(255))
tanka = db.Column(db.Integer)
def __init__(self, sname, tanka):
self.tanka = tanka
self.sname = sname
def __str__(self):
return f"{self.sid} {self.sname} {self.tanka}"
db.Integerで整数型、db.Stringで文字列型になります。Stringの場合、最大文字数を指定します。また、sidは主キーなので primary_key=True も付加します。
さらにクラス内にコンストラクタを作成しています。インスタンスを生成する際に指定する項目を決めるためです。ここではsnameとtankaを指定します。
str という関数は文字列化するときに自動で呼び出される関数です。printで表示をしやすくしています。
次にテーブルを作成します。これは以下のように行います。まず、テーブルを作成します。これはcreate_all() で可能ですが、その前に drop_all()でいったんテーブルを全削除するようにしています。実行時に毎回、ゼロから作るようにするためです。
with app.app_context():
db.drop_all() # テーブル全削除
db.create_all() # テーブル作成
なお、with app.app_context()はFlask-SQLAlchemyをコンソールで動かすために必要な設定です。この後に書くコードは全てこの配下に書いていきます。
ここで実行すると、instanceフォルダにhanbai.dbというファイルが作成されます。これを開くとshouhinテーブルがあるはずdす。
問題
db_uriage.py にて売上テーブルを作成しよう。クラス名はUriageとする。以下の列を作成する、
- 売上ID uid (整数:Integer) 主キー
- 商品ID sid (整数:Integer)
- 販売個数 kosu (整数:Integer)
- 販売日付 hi (日付:Date)
コンストラクタでは、引数をsidとkosuのみとする。コンストラクタ内で日付(hi)に今日の日付 datetime.today()を入れる
※実行し、hanbai.dbを開き、shouhinのところをuriageに変えるとデータを確認できる。
3 初期化
次に、初期データを設定します。最初にデータを配列に入れておきます。データはShouhinクラスのインスタンスとして生成します。
# 初期データ追加
data = [
Shouhin(sname="りんご", tanka=100),
Shouhin(sname="みかん", tanka=150),
Shouhin(sname="いちご", tanka=120),
]
db.session.add_all(data)
db.session.commit()
その後、db.session.add_all(配列)で全て追加されます。 ただし、db.session.commit() を最後にしないとこの結果が確定されません。データベースを更新(追加、変更、削除)した際にはこれが必要になることを覚えておきましょう。
実行すると、instanceフォルダにhanbai.dbが保存されます。これを開くと、データが入っていることが分かります。
問題
db_uriage.py にて以下のようなデータを初期データとして追加する。
- 一件目 sid:1 kosu:5
- 二件目 sid:2 kosu:3
- 三件目 sid:3 kosu:1
- 四件目 sid:1 kosu:2
4 全検索
では、設定した全データを表示してみます。わかりやすいように最初にprintで処理内容を表示しています。
Shouhin.query.all() でshouhinテーブルの全ての行を取得します。行は row と言いますので、rowsという変数に格納しています。それをfor文で r に取り出して表示しています。
print('全検索')
rows = Shouhin.query.all()
for r in rows:
print(r)
問題
db_uriage.py にて売上テーブルの結果を全検索して表示しよう。
5 検索
Shouhin.query.filter(条件)で条件を指定しての検索が可能です。条件式では列名を クラス名.列名 のように書きます。まず、tankaが120以上を抜き出してみます。
print('検索')
rows = Shouhin.query.filter(Shouhin.tanka >= 120).all()
for r in rows:
print(r)
文字列の検索の場合、containsを使って文字列を含む行を検索できます。
print('文字列検索')
rows = Shouhin.query.filter(Shouhin.sname.contains("ご")).all()
for r in rows:
print(r)
主キーで検索する場合、get(主キー) または get_or_404(主キー) というメソッドも使うことが出来ます。主キーでの検索は常に一件しか返ってきませんので、rowsではなく、rowに入れます。
print('主キー検索')
row = Shouhin.query.get_or_404(2)
print(row)
get_or_404の場合、存在しない場合には404ページを表示することが出来るので便利です(コンソールでは表示できません)。
問題
db_uriage.py にて売上テーブルでsidが1のデータを検索して全て表示しよう。
6 整列
全検索した結果を単価の昇順で並び替えます。これをqueryの後にorder_by関数を付けます。その引数に、db.asc("列名")、またはdb.desc("列名")を指定します。ascで昇順、descで降順になります。なお、昇順の場合には、db.asc()は省略して、"列名"だけでも可能です。
print('整列')
rows = Shouhin.query.order_by(db.desc('tanka')).all()
for r in rows:
print(r)
この並び替えは、filterの後にも使用可能です。
問題
db_uriage.py にて売上テーブルをsidの昇順に並び替えて表示しよう。
7 追加
初期化の時にデータを配列に入れて add_all(配列) で追加しましたが、一件のデータであれば、add(データ) で追加できます。
print('追加')
s = Shouhin(sname="ぶどう",tanka=300)
db.session.add(s)
db.session.commit()
確認のため、全表示してみます。
# 全表示
for r in Shouhin.query.all():
print(r)
問題
db_uriage.py にて売上テーブルに sid=2,kosu=1のデータを追加し、全検索しして表示しよう。
8 変更
既存データを変更するには、まず、get_or_404(主キー)を使って指定した主キーのデータを取得します。そして、属性を書き換えます。最後にcommitします。
print('変更')
row = Shouhin.query.get_or_404(4)
row.sname = "なし"
row.tanka = 200
db.session.commit()
確認のため、全表示してみます。
# 全表示
for r in Shouhin.query.all():
print(r)
問題
db_uriage.py にて売上テーブルの主キー uidが5のデータを sid=3,kosu=2に変更し、全検索しして表示しよう。
9 削除
既存データを削除するには、まず、get_or_404(主キー)を使って指定した主キーのデータを取得します。そして、db.session.delete(データ) とすれば削除されます。最後にcommitします。
print('削除')
row = Shouhin.query.get_or_404(4)
db.session.delete(row)
db.session.commit()
確認のため、全表示してみます。
# 全表示
for r in Shouhin.query.all():
print(r)
問題
db_uriage.py にて売上テーブルのuidが5のデータを削除しよう。