11-Flask

Flask(Part.9)| 【Flaskでデータベースを利用する方法(2)解説】

python| まとめ | 現役エンジニア&プログラミングスクール講師「python」のまとめページです。pythonに関して抑えておきたい知識や文法やにについて記事をまとめています。まとめページの下部には「おすすめの学習書籍」「おすすめのITスクール情報」「おすすめ求人サイト」について情報を掲載中...

目標

  • SQLiteについて概要が理解できる。
  • Flaskでデータベース利用の為のセットアップ(Flask-SQLAlchemyの導入)が行える。
  • Flaskを利用したデータベースの利用方法について理解できる。

Flaskでデータベースを利用する方法

SQLiteの概要(再掲載)

SQLiteは、非常に軽量で、サーバーを必要とせず、ファイルシステム上にデータベースを保存する組み込み型のデータベース管理システムです(サーバーとして動作せず、アプリケーションに直接組み込まれます。)。SQLiteには以下の特徴があります。

  • ファイルベース:SQLiteのデータは、単一のファイル(例えば、database.db)として保存されます。これにより、データベースを管理するためのサーバーを立てる必要がありません。
  • 軽量:小さなデータベースや開発段階でのテスト用のデータベースとして非常に適しています。サーバー型のデータベース(MySQLやPostgreSQL)に比べて、軽量で設定が簡単です。
  • ACIDトランザクション:SQLiteは、データの整合性を保つためのACID(Atomicity, Consistency, Isolation, Durability)トランザクションをサポートしています。


SQLiteを、Flaskと組み合わせることで、手軽にデータベースを利用したWebアプリケーションを開発できます。そのため、プロトタイピングで非常に便利です。

高負荷の並列処理や大量の同時書き込みがある場合は、MySQLやPostgreSQLの方が適しています。

FlaskとSQLiteの統合(再掲載)

FlaskアプリケーションとSQLiteの統合は、とても簡単で、Flask-SQLAlchemyというライブラリをインストールするだけでセットアップできます。

Flask-SQLAlchemyは、FlaskアプリケーションにSQLAlchemyを統合するための拡張ライブラリであり、Flaskでのデータベース操作を容易にします。SQLAlchemyはPythonのORM(Object-Relational Mapper)で、データベース操作をSQLでなく、Pythonのオブジェクトとして行うことができます。

FlaskはSQLiteを標準ではサポートしていませんが、sqlite3モジュールはPython標準ライブラリとして利用可能であり、Flask-SQLAlchemyなどのライブラリを追加することでFlaskで簡単にSQLiteを使用できるようになります。

更にFlaskでは、Flask-SQLAlchemyをセットアップすることで、一般的なリレーショナルデータベース(SQLite、MySQL、PostgreSQLなど)を使用できます。SQLiteはFlaskで利用できるデータベースの選択肢の1つです。

Flask-SQLAlchemyのインストール(再掲載)


Flask-SQLAlchemyをインストールします。

C:\Users\user\Desktop\FlaskProj>.venv\Scripts\activate

# 仮想環境が有効化されます。
(venv) C:\Users\user\Desktop\FlaskProj>pip install Flask-SQLAlchemy

FlaskアプリケーションでFlask-SQLAlchemyを使用するためにインポートします。

from flask_sqlalchemy import SQLAlchemy

Flask-SQLAlchemyライブラリの利用と解説

前回の記事では、models.pyというファイルをminiappディレクトリに作成して、商品モデルのクラスを準備し、app.pyからインポートしました。

FlaskでSQLAlchemyを使ってデータベースモデルを管理する際には、今回のような商品モデルをクラスの別ファイルにするのが一般的で、推奨されています。こうすることで、コードが整理され、アプリケーションが大きくなっても管理がしやすくなります。

Flaskアプリケーションを構築する際に、通常、モデル、ビュー、コントローラー(ルート)を分けて、よりモジュール化された構成にします。これにより、アプリケーションが拡張されても、コードが整理されていることもあり、可読性やメンテナンス性が向上します。(再掲載)

models.pyファイルの作成

前回の記事でmodels.pyファイルをminiappディレクトリに作成しました。

作成した models.pyファイル に次のプログラムを入力しました。

from flask_sqlalchemy import SQLAlchemy

# SQLAlchemyインスタンスを共通で使えるように
db = SQLAlchemy()


# 商品モデル(テーブル)の定義
class Product(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    price = db.Column(db.Integer, nullable=False)

    def __repr__(self):
        return f"<Product {self.id} - {self.name} - {self.price}>"

商品モデルクラスの解説

Flask-SQLAlchemyのインポート
from flask_sqlalchemy import SQLAlchemy

この行は、Flask-SQLAlchemyライブラリからSQLAlchemyクラスをインポートしています。Flask-SQLAlchemyは、FlaskアプリケーションにSQLAlchemy ORM(オブジェクトリレーショナルマッピング)を統合するためのライブラリです。このクラスは、データベースとの接続や操作を管理するためのものです。

SQLAlchemyインスタンスの作成
db = SQLAlchemy()

ここでは、SQLAlchemyのインスタンスを作成して、dbという変数に格納しています。このdbインスタンスは、Flaskアプリケーションでデータベースとの接続やモデルの定義、クエリの実行など、SQLAlchemyの操作に使用されます。

通常、Flaskアプリケーションでは、アプリケーションの設定後にこのdbインスタンスをFlaskアプリケーションにバインドします。

今回のアプリケーションではapp.pyファイルで生成し利用しています。次の設定は商品モデルクラスではなくapp.pyファイル内の記述です。

app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///example.db'  # SQLiteのデータベースのURI
db.init_app(app)
商品モデルの定義
class Product(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(100), nullable=False)
    price = db.Column(db.Integer, nullable=False)

    def __repr__(self):
        return f"<Product {self.id} - {self.name} - {self.price}>"

この部分は、データベースのテーブルを表すクラス(モデル)を定義しています。このクラスはSQLAlchemy ORMの特徴で、テーブルの各列をPythonのクラス属性として表現します。

db.Modelの継承

Productクラスは、db.Modelを継承しています。これにより、ProductクラスはSQLAlchemyのモデルとして機能し、データベースのテーブルと関連づけられます。

idカラム
id = db.Column(db.Integer, primary_key=True)

idはデータベースのINTEGER型のカラムで、商品ごとの一意な識別子(主キー)として機能します。primary_key=Trueによって、このカラムが主キーであることが示されます。主キーは各レコードを一意に識別するため、重複しない値である必要があります。

nameカラム
name = db.Column(db.String(100), nullable=False)

nameはデータベースのSTRING型のカラムで、商品の名前を格納します。
nullable=Falseは、このカラムにNULLが許可されないことを意味します。つまり、商品名は必須項目であり、空の値は保存できません。

priceカラム
name = db.Column(db.String(100), nullable=False)

price = db.Column(db.Integer, nullable=False)
priceは商品の価格を格納するINTEGER型のカラムです。
nullable=Falseは、価格も必須項目であることを意味します。

__repr__メソッド
def __repr__(self):
    return f"<Product {self.id} - {self.name} - {self.price}>"

__repr__は、Pythonのオブジェクトの文字列表現を定義する特殊メソッドです。このメソッドは、Productオブジェクトが文字列として表示されるときのフォーマットを指定します。

この例では、Productオブジェクトが文字列に変換されるとき、<Product id – name – price>という形式で出力されます。これにより、オブジェクトの情報が見やすく表示されます。

このコードの全体的な目的

このプログラムは、商品情報(商品ID、名前、価格)を保存するためのデータベースモデルを定義しています。Productクラスは、商品のデータをデータベースのテーブルとして管理し、SQLAlchemy ORMを使ってデータベース操作を行えるようにします。

商品の追加

new_product = Product(name="Apple", price=100)
db.session.add(new_product)
db.session.commit()

商品のクエリ(取得)

product = Product.query.get(1)  # id=1の商品の取得

商品の更新

product.price = 200
db.session.commit()

app.pyの編集内容

次のプログラムは、前回の記事で行ったapp.pyの編集後の内容です。

from flask import Flask, redirect, render_template, url_for

from apps.miniapp.forms import AddProductForm
from apps.miniapp.models import Product, db  # models.pyからインポート

# アプリケーションの初期化
app = Flask(__name__)
app.secret_key = "your_secret_key"

# SQLiteの設定
app.config["SQLALCHEMY_DATABASE_URI"] = (
    "sqlite:///products.db"  # SQLiteデータベースファイル
)
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False  # 不要な変更追跡を無効化

# SQLAlchemyのインスタンスを初期化
db.init_app(app)


# アプリケーションコンテキスト内でテーブル作成
with app.app_context():
    db.create_all()


# ルート: トップページ
@app.route("/")
def index():
    return "Top page"


# ルート: 商品一覧ページ
@app.route("/products")
def product_list():
    products = Product.query.all()  # SQLiteから商品データを取得
    return render_template("products.html", products=products)


# ルート: 商品追加ページ
@app.route("/add_product", methods=["GET", "POST"])
def add_product():
    form = AddProductForm()

    if form.validate_on_submit():
        # フォームが送信され、バリデーションが成功した場合
        name = form.product_name.data
        price = form.product_price.data

        # 新しい商品をデータベースに追加
        new_product = Product(name=name, price=price)
        db.session.add(new_product)  # セッションに追加
        db.session.commit()  # データベースにコミット

        # 商品一覧ページにリダイレクト
        return redirect(url_for("product_list"))

    return render_template("add_product.html", form=form)


# ルート: 商品管理ページ
@app.route("/manage_products")
def manage_products():
    return render_template("manage_products.html")


if __name__ == "__main__":
    app.run(debug=True)

修正内容の解説

Productモデルの作成
from apps.miniapp.models import Product, db  # models.pyからインポート

models.pyからProductクラスとdbインスタンスをインポートしています。
Productは、データベースのテーブル(商品データ)を表すORMクラスで、db.Modelを継承しており、id, name, priceのカラムを持っています。dbはSQLAlchemyのインスタンスで、データベースへの接続や操作を管理します。

SQLAlchemyの設定
# SQLiteの設定
app.config["SQLALCHEMY_DATABASE_URI"] = (
    "sqlite:///products.db"  # SQLiteデータベースファイル
)
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False  # 不要な変更追跡を無効化
  • app.config[‘SQLALCHEMY_DATABASE_URI’] = ‘sqlite:///products.db’: SQLiteデータベースをproducts.dbというファイルに保存します。
  • app.config[‘SQLALCHEMY_TRACK_MODIFICATIONS’] = False: 不要な変更追跡を無効にして、アプリケーションのパフォーマンスを向上させます。
SQLAlchemyのインスタンスを初期化
db.init_app(app)

db.init_app(app)で、FlaskアプリケーションにSQLAlchemyを初期化しています。

アプリケーションコンテキスト内でデータベーステーブルの作成
with app.app_context():
    db.create_all()

このコードは、Flaskアプリケーションのコンテキスト内でデータベースのテーブルを作成します。db.create_all()は、アプリケーション内で定義されたすべてのモデルに基づいてテーブルを自動的に作成します。これにより、最初に実行した際にデータベースに必要なテーブル(例えば、Productテーブル)が作成されます。

データベースの操作(商品一覧の取得)
# ルート: 商品一覧ページ
@app.route("/products")
def product_list():
    products = Product.query.all()  # SQLiteから商品データを取得
    return render_template("products.html", products=products)

Product.query.all()は、Productテーブルからすべてのレコード(商品)を取得するクエリです。これにより、データベースに保存されている商品データが全て取得され、productsとしてテンプレートに渡されます。

render_template(“products.html”, products=products)で、商品データをproducts.htmlテンプレートに渡して表示します。

データベースの操作(商品の追加)
# ルート: 商品追加ページ
@app.route("/add_product", methods=["GET", "POST"])
def add_product():
    form = AddProductForm()

    if form.validate_on_submit():
        # フォームが送信され、バリデーションが成功した場合
        name = form.product_name.data
        price = form.product_price.data

        # 新しい商品をデータベースに追加
        new_product = Product(name=name, price=price)
        db.session.add(new_product)  # セッションに追加
        db.session.commit()  # データベースにコミット

        # 商品一覧ページにリダイレクト
        return redirect(url_for("product_list"))

    return render_template("add_product.html", form=form)

この部分は商品をデータベースに追加するための機能です。AddProductFormは、商品名と価格を入力するフォームです。フォームが送信されてバリデーションが成功すると、フォームからデータ(商品名と価格)を取得し、それを使って新しいProductインスタンスを作成します。

db.session.add(new_product)で新しい商品をセッションに追加し、db.session.commit()でデータベースに保存します。

db.session.add(new_product)で、new_productをセッションに追加します。この時点ではデータベースにはまだ保存されません。
db.session.commit()を呼ぶことで、セッション内の変更がデータベースに実際に保存されます。これにより、新しい商品がproducts.dbに永続化されます。

テンプレートの修正はなし

products.html と add_product.html のテンプレートをそのまま利用することができます。products.htmlでは、productsというリストをループして商品の一覧を表示する形にします。

add_product.htmlの商品追加フォームの内容。

<!DOCTYPE html>
<html lang="ja">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>商品追加</title>
    <link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
</head>

<body>

    <h1>商品追加ページ</h1>
    <ul>
        <li><a href="{{ url_for('product_list') }}" class="button-link">商品一覧に戻る</a></li>
        <li><a href="{{ url_for('manage_products') }}" class="button-link">商品管理ページ</a></li>
    </ul>

    <h1>商品追加フォーム</h1>

    <form method="POST" action="{{ url_for('add_product') }}">
        {{ form.hidden_tag() }} <!-- CSRFトークンを含めるため -->

        <label for="product_name">商品名</label>
        {{ form.product_name() }} <!-- 商品名入力フィールド -->
        {% if form.product_name.errors %}
        <ul>
            {% for error in form.product_name.errors %}
            <li>{{ error }}</li>
            {% endfor %}
        </ul>
        {% endif %}

        <label for="product_price">価格</label>
        {{ form.product_price() }} <!-- 価格入力フィールド -->
        {% if form.product_price.errors %}
        <ul>
            {% for error in form.product_price.errors %}
            <li>{{ error }}</li>
            {% endfor %}
        </ul>
        {% endif %}

        <input type="submit" value="商品を追加する">
    </form>

</body>

</html>

ブラウザで http://127.0.0.1:5000/manage_productsにアクセスします。

商品管理ページが表示されます。

商品一覧ボタンを押下すると、商品一覧ページが表示されます。始めて開いた状態では商品一覧には何もありません。

商品を追加するボタンを押下すると、商品追加ページが表示されます。

商品名と価格を入力して「商品を追加する」ボタンを押下します。

http://127.0.0.1:5000/products にリダイレクトされます。

商品が追加されています。このデータベースはVisual Studio Codeのエクスプローラーで確認ができます。今回の場合は、 instanceディレクトリの中に、products.db というファイルで生成されているのが確認できます。

データベースを初期化するには、この products.db ファイルを削除します。

続けて、商品追加ページで商品名を空で送信ボタンを押下します。

商品の追加はされず、商品追加ページが再表示されます。

今回は以上になります。

「python」おすすめ書籍 ベスト3 | 現役エンジニア&プログラミングスクール講師「python」の学習でお勧めしたい書籍をご紹介しています。お勧めする理由としては、考え方、イメージなどを適切に捉えていること、「生のpython」に焦点をあてて解説をしている書籍であることなどが理由です。勿論、この他にも良い書籍はありますが、特に質の高かったものを選んで記事にしています。ページの下部には「おすすめのITスクール情報」「おすすめ求人サイト」について情報を掲載中。...

ブックマークのすすめ

「ほわほわぶろぐ」を常に検索するのが面倒だという方はブックマークをお勧めします。ブックマークの設定は別記事にて掲載しています。

「お気に入り」の登録・削除方法【Google Chrome / Microsoft Edge】「お気に入り」の登録・削除方法【Google Chrome / Microsoft Edge】について解説している記事です。削除方法も掲載しています。...
【パソコン選び】失敗しないための重要ポイント | 現役エンジニア&プログラミングスクール講師【パソコン選び】失敗しないための重要ポイントについての記事です。パソコンのタイプと購入時に検討すべき点・家電量販店で見かけるCPUの見方・購入者が必要とするメモリ容量・HDDとSSDについて・ディスプレイの種類・バッテリーの持ち時間や保証・Officeソフト・ウィルス対策ソフトについて書いています。...
RELATED POST
11-Flask

Flask(Part.13)| 【ふたつのテーブルの利用(3)テンプレート部分の解説】

2025年3月6日
プログラミング学習 おすすめ書籍情報発信 パソコン初心者 エンジニア希望者 新人エンジニア IT業界への就職・転職希望者 サポートサイト Programming learning Recommended schools Recommended books Information dissemination Computer beginners Prospective engineers New engineers Prospective job seekers in the IT industry Support site
11-Flask

Flask(Part.11)| 【ふたつのテーブルの利用(1)実装と実行】

2025年3月4日
プログラミング学習 おすすめ書籍情報発信 パソコン初心者 エンジニア希望者 新人エンジニア IT業界への就職・転職希望者 サポートサイト Programming learning Recommended schools Recommended books Information dissemination Computer beginners Prospective engineers New engineers Prospective job seekers in the IT industry Support site