【Flask】SQLiteで基本的なデータ操作を学ぼう|Chapter5-3

一つ前のページではデータベースの作成方法について学習しました。
今回は データベースの操作方法 について見ていきましょう。
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:エラーハンドリングとデバッグ編
Chapter7:アプリ開発編
前回(Chapter5-2)は SQLiteを使って空のデータベースとテーブルを作成しました。
これによってデータを保存する「箱」のようなものが用意できたわけです。今回はいよいよ、その「箱」に実際のデータを出し入れする操作を学びます。
具体的には、以下のような操作を学びます:
- Create(作成):データの新規登録
- Read(読み取り):データの読み取り
- Update(更新):データの変更
- Delete(削除):データの削除
これらは頭文字を取って「CRUD」と呼ばれ、すべてのデータ操作の基本になります。
頭の中でエクセルの表をイメージし、各セルの情報を直接変更するのではなく、外部からの命令(コード)で修正させるイメージを持ちましょう。
- この表のあの列の各セルに、上から順にこれらのデータを書き込め
- この行の〇〇番目のデータを全て削除しろ
- etc…
- Flask開発を Stream Deck でボタン化しよう!
-
Flaskは非常に軽量かつシンプルなフレームワークですが、それゆえに定型作業が多く、開発は単調な作業の連続になりがちです。
それこそがFlaskのメリットであり、習得難易度が低い理由でもありますが、単調な作業は退屈で、ミスも起こりやすいでしょう。
そこで役に立つのが Stream Deck 。
このような定型手順が多い作業を “ボタン化” することで視覚化。
圧倒的に 効率的 かつ ストレスフリー な開発環境が簡単に手に入ります↓↓
あわせて読みたいFlask開発をStreamDeckでボタン化しようあわせて読みたいプログラマー向けStream Deckの選び方|初心者でも失敗しないモデル比較ガイド
データベースの操作準備|前回のコードを再利用しよう
今回のこの記事は、Chapter5-2で作成したコードをベースとして、追記していく形式となっています。
各コードをコピーして、conn.close()メソッドの前に 順番に貼り付けながら読んでいきましょう。
Chapter5-2で作成したコードは以下の通りです。このコード内に分からない部分がある場合は、先にChapter5-2に記事に戻って復習しましょう。
- Chapter5-2のコード
-
import sqlite3 # 組み込み型データベース「SQLite」を操作するためのsqlite3モジュールをインポート from pathlib import Path # pathlibライブラリのPathクラスをインポート # ==================================== # データベースのパス(保存場所)を設定 # ==================================== base_dir = Path(__file__).parent # このスクリプトファイルがあるフォルダのパスを取得して、変数base_dirに代入 database = 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('▲▲▲ 接続終了 ▲▲▲')

データを追加する|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()メソッド を実行して変更を確定させます。
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()メソッド と cur.fetchone()メソッド
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 を使って、さらに効率的で安全なデータ操作を学んでいきます。
データベース操作の自動化の世界へ、一歩踏み出しましょう!
- サイト改善アンケート|1分だけ、ご意見をお聞かせください
-
本サイトでは、みなさまの学習をよりサポートできるサービスを目指しております。
そのため、ご利用者のみなさまの「プログラミングを学習する理由」などをアンケート形式でお伺いしています。ご協力いただけますと幸いです。
アンケート
FAQ|SQLiteでデータを操作する方法FAQ|
- Q1. cur.execute()とcur.executemany()の違いは何ですか?
-
cur.execute()は1つのSQL文を実行する際に使います。複数のデータを一括登録したい場合は、cur.executemany()を使うと効率的です。
- Q2. fetchall()とfetchone()はどう使い分ければ良いですか?
-
fetchall()はSELECT文で取得したすべての結果をリスト形式で返します。一方、fetchone()は最初の1件だけを返すので、データ量が少ない場合や1件だけ必要な時に使います。
- Q3. データ更新や削除後に表示結果が変わらないのはなぜですか?
-
更新や削除後にconn.commit()を忘れると変更が確定されません。必ずcommit()を実行してから再度SELECT文でデータを確認しましょう。






