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円)ですが、現在は期間限定で 無料公開中 です。
データベースの操作準備|前回のコードを再利用しよう
今回のこの記事は、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('▲▲▲ 接続終了 ▲▲▲')
データを追加する|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()
メソッド を実行して変更を確定させます。
データを読み込む|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件だけを取得するメソッドです。
データを更新する|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 を使って、さらに効率的で安全なデータ操作を学んでいきます。
データベース操作の自動化の世界へ、一歩踏み出しましょう!
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文でデータを確認しましょう。