Flask-SQLAlchemyは以下のようにしてインストールします。
pip install Flask-SQLAlchemy
VisualStudio CodeにSQLiteのファイルを扱う拡張機能「SQLite3 Editor」をインストールしておきます。コマンドラインで以下から可能です。
code --install-extension yy0931.vscode-sqlite3-editor
もしくはVisualStudio Code画面左の拡張機能のボタンを押して、「SQLite3 Editor」と入力します。
Flask-SQLAlchemyを使うには通常のようにFlaskのオブジェクトを作り、その設定でファイル名を指定します。また、SQLAlchemyのオブジェクトを作成します。
from flask import Flask, render_template, request, redirect from flask_sqlalchemy import SQLAlchemy from datetime import datetime app = Flask(__name__) app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///hanbai.db' db = SQLAlchemy(app)
今回は商品を管理する以下のようなテーブルを作成します。
そのために、商品テーブルのデータを一件入れるためのクラス、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で表示をしやすくしています。
テーブルを作成するようには以下のように行います(いったん全削除して再作成しています)。with app.app_context() はweb環境では無いコンソールなどで必要な処理です。その配下にデータベース操作を記述します。
with app.app_context(): db.drop_all() # テーブル全削除 db.create_all() # テーブル作成
ここで実行すると、instanceフォルダにhanbai.dbというファイルが作成されます。これを開くとshouhinテーブルがあるはずです。
次に、初期データを設定します。最初にデータを配列に入れておきます。データはShouhinクラスのインスタンスとして生成します。
# 初期データ追加 data = [ Shouhin(sname="りんご", tanka=100), Shouhin(sname="みかん", tanka=150), Shouhin(sname="いちご", tanka=120), ] db.session.add_all(data) db.session.commit()
では、設定した全データを表示してみます。
Shouhin.query.all() でshouhinテーブルの全ての行を取得します。行は row と言いますので、rowsという変数に格納しています。それをfor文で r に取り出して表示しています。
rows = Shouhin.query.all() for r in rows: print(r)
Shouhin.query.filter(条件)で条件を指定しての検索が可能です。条件式では列名を クラス名.列名 のように書きます。
# tankaが120以上 rows = Shouhin.query.filter(Shouhin.tanka >= 120).all() # 複数条件 rows = Uriage.query.filter(Uriage.sid == 1, Uriage.kosu > 1).all() # 一件のみ rows = Shouhin.query.filter(Shouhin.sid == 1).first() # 文字列の検索 rows = Shouhin.query.filter(Shouhin.sname.contains("ご")).all()
主キーで検索する場合、get(主キー) または get_or_404(主キー) というメソッドも使うことが出来ます。主キーでの検索は常に一件しか返ってきませんので、rowsではなく、rowに入れます。
row = Shouhin.query.get(2) row = Shouhin.query.get_or_404(2)
全検索した結果を単価の昇順で並び替えます。これをqueryの後にorder_by関数を付けます。その引数に、db.asc("列名")、またはdb.desc("列名")を指定します。ascで昇順、descで降順になります。なお、昇順の場合には、db.asc()は省略して、"列名"だけでも可能です。
# 単価の昇順 rows = Shouhin.query.order_by('tanka').all() # 単価の昇順 rows = Shouhin.query.order_by(db.asc('tanka')).all() # 単価の降順 rows = Shouhin.query.order_by(db.desc('tanka')).all()
データを一件追加するには、インスタンスを作成し、db.session.addで追加します。最後に db.session.commit() を行わないとこの変更が保存されません。
s = Shouhin(sname="ぶどう",tanka=300) db.session.add(s) db.session.commit()
既存データを変更するには、まず、get_or_404(主キー)を使って指定した主キーのデータを取得します。そして、属性を書き換えます。最後にcommitします。
row = Shouhin.query.get_or_404(4) row.sname = "なし" row.tanka = 200 db.session.commit()
既存データを削除するには、まず、get_or_404(主キー)を使って指定した主キーのデータを取得します。そして、db.session.delete(データ) とすれば削除されます。最後にcommitします。
row = Shouhin.query.get_or_404(4) db.session.delete(row) db.session.commit()
結合を行う場合、まず一対多の「一」の方でモデルクラス内にて db.relationship を記述する。これは、多の方のクラスのリストを持つ、という意味である。このとき、backrefを設定することで「多」のクラスの方でも「一」の方をその名前で参照できる。
uriage = db.relationship('Uriage', backref='shouhin', lazy=True)
「多」の方では、外部キーの設定を行う。
sid = db.Column(db.Integer, db.ForeignKey('shouhin.sid'))
全体像
class Shouhin(db.Model): sid = db.Column(db.Integer, primary_key=True) sname = db.Column(db.String(255)) tanka = db.Column(db.Integer) uriage = db.relationship('Uriage', backref='shouhin', lazy=True) def __init__(self, sname, tanka): self.sname = sname self.tanka = tanka def __str__(self): return f"{self.sid} {self.sname} {self.tanka}" class Uriage(db.Model): uid = db.Column(db.Integer, primary_key=True) sid = db.Column(db.Integer, db.ForeignKey('shouhin.sid')) kosu = db.Column(db.Integer) hi = db.Column(db.Date) def __init__(self, sid , kosu): self.sid = sid self.kosu = kosu self.hi = datetime.today() def __str__(self): return f"{self.uid} {self.sid} {self.kosu} {self.hi}"
これにより多の方から一を参照できる。
results = Uriage.query.all() for uriage in results: print(uriage.uid, uriage.shouhin.sname, uriage.kosu, uriage.hi)
また、一方から多を参照できる。
rows = Shouhin.query.all() for r in rows: print(r) for u in r.uriage: print(u)