Flask入門|SQLiteで基本的なデータ操作を学ぼう【チャプター5-03】

ながみえ

一つ前のページではデータベースの作成方法について学習しました。

今回は データベースの操作方法 について見ていきましょう。

Chapter1:Flask入門編
Chapter2:Jinja2入門編
Chapter3:フィルター編
Chapter4:フォーム編
Chapter5:データベース編

 ・Chapter5-1:データベースとは何か
 ・Chapter5-2:データベースを作ろう
 ・Chapter5-3:データベースを操作しよう ◁今回はここ
 ・Chapter5-4:SQLAlchemyを使おう
 ・Chapter5-5:内部結合と外部結合を理解しよう
 ・Chapter5-6:relationshipを理解しよう
 ・Chapter5-7:Flask-SQLAlchemyを使おう
 ・Chapter5-8:Flask-Migrateを使おう
Chapter6:Flaskの便利機能編
Chapter7:アプリ開発編

前回の [Chapter5-2] では、SQLiteを使って空のデータベースとテーブルを作成しました。

これによって、データを保存する「箱」のようなものが用意できたわけです。今回はいよいよ、その「箱」に実際のデータを出し入れする操作を学びます。

具体的には、以下のような操作を学びます:

  • Create(作成):データの新規登録
  • Read(読み取り):データの読み取り
  • Update(更新):データの変更
  • Delete(削除):データの削除

これらは頭文字を取って「CRUD」と呼ばれ、すべてのデータ操作の基本になります。

頭の中でエクセルの表をイメージし、各セルの情報を直接変更するのではなく、外部からの命令(コード)で修正させるイメージを持ちましょう。

  • この表のあの列の各セルに、上から順にこれらのデータを書き込め
  • この行の〇〇番目のデータを削除しろ
  • etc…

本記事は 有料記事(100円)ですが、現在は期間限定で 無料公開中 です。

<<前のページ

Flaskの記事一覧

次のページ>>

データベースの操作準備|前回のコードを再利用しよう

今回のこの記事は、Chapter5-2で作成したコードをベースとして、追記していく形式となっています。

各コードをコピーして、conn.close()メソッドの前に 順番に貼り付けながら読んでいきましょう。

Chapter5-2で作成したコードは以下の通りです。このコード内に分からない部分がある場合は、先にChapter5-2に記事に戻って復習しましょう。

import os      # ファイルやディレクトリ操作で使用する標準ライブラリ「os」をインポート
import sqlite3 # 組み込み型データベース「SQLite」を操作するためのsqlite3モジュールをインポート

# ====================================
# データベースのパス(保存場所)を設定
# ====================================
base_dir = os.path.dirname(__file__)             # このスクリプトファイルがあるフォルダのパスを取得して、変数base_dirに代入
database = os.path.join(base_dir, 'data.sqlite') # base_dir内のdata.sqliteというファイルへのパスを作成し、変数databaseに代入

# ====================================
# データベース接続とカーソルの初期化
# ====================================
## 接続オブジェクト
conn = sqlite3.connect(database) # databaseパスにSQLiteのデータベースを作成or接続し、接続オブジェクトconnに代入
print('▼▼▼ 接続開始 ▼▼▼')    # データベース接続開始を示すログ出力
print()                          # 空行を出力してログの見やすさを確保

## カーソルオブジェクト
cur = conn.cursor() # SQL文を実行するためのカーソルオブジェクトを作成(インスタンス生成)し、変数curに代入

# ====================================
# SQL操作の実行
# ====================================
## テーブルを初期化
drop_sql = """
    DROP TABLE IF ExISTS items; 
""" # items というテーブル(表)が存在する場合は削除するSQL文を、変数drop_sqlに代入
cur.execute(drop_sql) # .executeメソッドでdrop_sqlを実行 ⇒ 対象テーブルを削除
print('対象テーブルがあれば削除')

## テーブルを作成
create_sql = """
    CREATE TABLE items(
        item_id INTEGER PRIMARY KEY AUTOINCREMENT,
        item_name STRING UNIQUE NOT NULL,
        age INTEGER NOT NULL
    );
""" # items というテーブルを作るSQL文を、変数create_sqlに代入
cur.execute(create_sql) # .executeメソッドでcreate_sqlを実行 ⇒ テーブルを作成
print('テーブル作成')

# ★★★★★★★★★★★★★★★★★★★★★
# ここにChapter5-3のコードを追記していこう
# ★★★★★★★★★★★★★★★★★★★★★

# ====================================
# データベースとの接続を閉じる
# ====================================
conn.close() # 処理が終わったら明示的に接続を閉じる
print()
print('▲▲▲ 接続終了 ▲▲▲')
【Python】勉強猫がノートパソコンを前にして学習を始める様子。記事内の学習スタート用イラスト

データを追加する|INSERT文で新規登録

まずはテーブルに新しいデータを登録(INSERT)してみましょう。

## データを追加
insert_sql = """
    INSERT INTO items(item_name, age)VALUES(?, ?)
""" # 「itemsテーブルにデータを追加する」というSQL文を、変数insert_sqlに代入
    # (?, ?) はプレースホルダー:後で実データを代入する
insert_data_list = [
    ('私',20),('父',50),('母',45)
] # 登録するタプルデータを変数insert_data_listに代入
cur.executemany(insert_sql, insert_data_list) # .executemanyメソッドで各タプルを insert_sql の ?, ? に順番に代入
conn.commit() # 登録内容を確定(コミット)
print('データ追加:実行')
  • INSERT INTO は、テーブルにデータを追加するSQL文です。
  • VALUES (?, ?)?プレースホルダー と呼ばれ、後から実際の値が代入されます。
  • cur.executemany()メソッド でリスト内の複数データをまとめて登録できます。
  • conn.commit()メソッド を実行して変更を確定させます。
あわせて読みたい
Pythonデータ構造|タプルの基本操作をマスターしよう|splitとjoinの実例付き【レッスン4-9】
Pythonデータ構造|タプルの基本操作をマスターしよう|splitとjoinの実例付き【レッスン4-9】
cur.executemany()メソッド

データベースに複数のデータを登録したいとき、1件ずつ .execute() で登録するのはとても面倒です。

cur.execute(insert_sql, ('私', 20))
cur.execute(insert_sql, ('父', 50))
cur.execute(insert_sql, ('母', 45))

このように毎回 cur.execute() を書くとコードが長くなるうえ、ミスのもとにもなります。

そこで登場するのが、.executemany()メソッドです。

cur.executemany(SQL文, データのリスト)

1つのSQL文に対して複数のデータを一括で実行できます。

conn.commit()メソッド

データベースに対して「データの追加・更新・削除」といった変更操作を行った場合、以下のようなコードが必要になります。

conn.commit()

このメソッドは、データベース操作を確定(保存)するための命令です。

SQLite では、変更操作を行ってもそれだけではまだデータベースファイル(例:data.sqlite)に書き込まれていない状態です。

これは、処理の途中で問題が発生した場合に、元に戻せるようにするためです。

このような仕組みを「トランザクション」と呼び、変更を最終的に保存するためには commit() が必要となります。

データを読み込む|SELECT文で情報を取得

次に、テーブルに登録されているデータを読み取る(SELECT)方法を学びます。

## 全てのデータを参照
select_all_sql = """
    SELECT * FROM items
""" # 全データを取得するSQL文を変数select_all_sqlに代入
cur.execute(select_all_sql) # .executeメソッドでselect_all_sqlを実行 ⇒ 全データ取得
print('--- 全件取得:実行 ---')
data = cur.fetchall() # .fetchall()メソッドで取得データを受け取り、変数dataに代入
print(data)

## 1件のデータを参照
select_one_sql = """
    SELECT * FROM items WHERE item_id = ?
""" # item_id が一致する1件だけを取得するSQL文を、変数select_one_sqlに代入
    # ? はプレースホルダー:後で実データを代入する
id = 3
cur.execute(select_one_sql, (id,)) # .executeメソッドでselect_one_sqlを実行 ⇒ データ取得
print('--- 1件取得:実行 ---')
data = cur.fetchone() # .fetchone()メソッドで取得データの最初の1行を受け取り、変数dataに代入
print(data)
  • SELECT * FROM items は、itemsテーブルのデータ取得を意味します。
  • cur.fetchall()メソッド で全ての結果をリスト形式で取得できます。
  • cur.fetchone()メソッド は最初の1件だけを取得するメソッドです。
cur.fetchall()

SQLite においてデータを読み取る際には、SELECT 文を実行したあとに、結果を受け取るメソッドとして fetchall()fetchone() が使われます。

これらはどちらも「データを取得する」ためのものですが、取得する量と用途に違いがあります。

目的適したメソッド
全件をまとめて取得したい場合fetchall()
特定の1件だけを取得したい場合fetchone()
1件ずつ順番に処理したい場合(ループ)fetchone()(複数回使用)

たとえばログイン機能やID検索など、条件がユニークな場合は fetchone() を、一覧表示のような場面では fetchall() を使うのが一般的です。

どちらも結果を取得するためのメソッドですが、用途に応じて使い分けることで、コードの効率性と可読性を向上させることができます。

操作対象のデータ量や目的に応じて、適切な選択を心がけましょう。

データを更新する|UPDATE文で既存情報を修正

既存のデータを修正したい場合は、UPDATE文を使います。

## データを更新
update_sql = """
    UPDATE items SET age=? WHERE item_id= ?
""" # item_idが指定する行のageを変更するSQL文を、変数update_sqlに代入
    # ? はプレースホルダー:後で実データを代入する
age = 21
id = 1
cur.execute(update_sql, (age, id)) # .executeメソッドでupdate_sqlを実行 ⇒ データ更新
print('--- データ更新:実行 ---')
conn.commit()                      # 更新内容を確定(コミット)
cur.execute(select_one_sql, (id,)) # 以下、「1件のデータを参照」部分と同じ
data = cur.fetchone()
print('確認のため1件取得:実行',data)
  • UPDATE items SET で、特定のレコードの指定列を更新します。
  • WHERE を忘れると、全ての行が更新されるため要注意。
  • cur.execute()メソッド でSQLを実行し、cur.commit() で変更を保存。

データを削除する|DELETE文で不要データを削除

最後に、不要になったデータを削除(DELETE)する方法を学習します。

## データを削除
delete_sql = """
    DELETE FROM items WHERE item_id= ?
""" # item_id が一致するレコードだけを削除するSQL文を、変数delete_sqlに代入
    # ? はプレースホルダー:後で実データを代入する
id =3
cur.execute(delete_sql, (id,)) # .executeメソッドでdelete_sqlを実行 ⇒ データ削除
conn.commit()                  # 更新内容を確定(コミット)
print('--- データ削除:実行 ---')
cur.execute(select_all_sql)    # 以下、「全てのデータを参照」部分と同じ
data = cur.fetchall()
print('確認のため全件取得:実行', data)
  • DELETE FROM はデータ削除に使います。
  • WHERE がないと全データが消えてしまうので必ず指定しましょう。
  • 削除後は cur.commit() を忘れずに。

まとめ|基本的なCEUD操作をしっかり理解しよう

この記事では、SQLiteでの基本的なデータ操作(CEUD)を学びました。

操作名内容
Createデータの追加
Readデータの読み取り
Updateデータの更新
Deleteデータの削除

Chapter5-2の記事でも述べたように、Flaskを身に付ける上で SQL言語自体を覚える必要はありません。

Chapter5-4で学習するSQLAlchemyを用いれば、Pythonだけで記述することができます。

SQLがどのように使用されているかをイメージできるようになれば十分です。それよりもDBに関連する主要なメソッドを覚えましょう。

メソッド(記述)役割・意味
conn = sqlite3.connect('data.sqlite')SQLiteデータベースに接続し、接続オブジェクトを作成する
conn.commit()データの追加・更新・削除などの変更内容を確定(保存)する
conn.close()データベースとの接続を終了してリソースを解放する
cur = conn.cursor()SQL文を実行するためのカーソルオブジェクトを作成する
cur.execute(SQL文)SQL文を1つ実行する(例:テーブル作成、データ選択、更新など)
cur.executemany(SQL文, データリスト)同じSQL文を複数のデータに対して一括で実行する
cur.fetchall()SQLのSELECT文で得られた結果をすべて取得し、リストとして返す
cur.fetchone()SQLのSELECT文で得られた結果から1件だけ取得し、タプルで返す

次回は、ORM(Object Relational Mapper)である SQLAlchemy を使って、さらに効率的で安全なデータ操作を学んでいきます。

データベース操作の自動化の世界へ、一歩踏み出しましょう!

もっと分かりやすい学習サイトにするために

この記事を読んで「ここが分かりにくかった」「ここが難しかった」等の意見を募集しています。

世界一わかりやすいFlask学習サイトにするため、ぜひ 問い合わせフォーム からご意見下さい。

<<前のページ

Flaskの記事一覧

次のページ>>

FAQ|SQLiteでデータを操作する方法FAQ|

Q
Q1. cur.execute()とcur.executemany()の違いは何ですか?

cur.execute()は1つのSQL文を実行する際に使います。複数のデータを一括登録したい場合は、cur.executemany()を使うと効率的です。

Q
Q2. fetchall()とfetchone()はどう使い分ければ良いですか?

fetchall()はSELECT文で取得したすべての結果をリスト形式で返します。一方、fetchone()は最初の1件だけを返すので、データ量が少ない場合や1件だけ必要な時に使います。

Q
Q3. データ更新や削除後に表示結果が変わらないのはなぜですか?

更新や削除後にconn.commit()を忘れると変更が確定されません。必ずcommit()を実行してから再度SELECT文でデータを確認しましょう。

記事URLをコピーしました