2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

はじめに

先日はPythonでSQLiteを操作する方法を紹介しました。
Pythonの標準ライブラリであるTkinterを使用してGUIアプリケーションを作成し、SQLiteのデータを操作するツールの作成方法を紹介します。

事前準備

開発環境

開発環境は以下です。

  • Windows11
  • Python 3.12.0
  • SQLite

ファイル構成

ファイルの構成と各ファイルの役割は以下です。

project/
├── app.py
├── repository.py
└── sample.db
  • app.py : Tkinterを使用したGUI部分のコード
  • repository.py : SQLiteを操作するコード
  • sample.db : SQLiteのデータベースファイル

テーブル構造とサンプルデータ

今回のツール作成で使用するテーブルとサンプルデータは以下のようになります。

BEGIN TRANSACTION;
CREATE TABLE employees (
    id INTEGER PRIMARY KEY,
    name TEXT NOT NULL,
    department TEXT NOT NULL,
    position TEXT NOT NULL,
    salary INTEGER NOT NULL,
    hire_date TEXT NOT NULL
);

INSERT INTO employees VALUES(1,'山田太郎','開発部','社員',3800000,'2021-03-15');
INSERT INTO employees VALUES(2,'佐藤花子','開発部','主任',4500000,'2020-07-20');
INSERT INTO employees VALUES(3,'鈴木一郎','開発部','課長',5800000,'2018-11-01');
INSERT INTO employees VALUES(4,'高橋美咲','営業部','社員',3600000,'2022-01-10');
INSERT INTO employees VALUES(5,'伊藤健太','営業部','主任',4300000,'2020-05-03');
INSERT INTO employees VALUES(6,'渡辺翔','営業部','課長',5500000,'2017-09-18');
INSERT INTO employees VALUES(7,'中村彩','人事部','社員',3500000,'2023-02-01');
INSERT INTO employees VALUES(8,'小林大輔','人事部','主任',4400000,'2019-12-11');
INSERT INTO employees VALUES(9,'加藤優子','経理部','主任',4700000,'2021-06-30');
INSERT INTO employees VALUES(10,'吉田誠','経理部','課長',6200000,'2016-08-22');
COMMIT;

Tkinterを使用したDB管理ツールの作成

1. データの表示と検索

まずは、データの表示と検索機能を作成します。
検索の「名前」のテキストボックスに名前を入力して「検索」ボタンを押すと、名前が部分一致するデータを表示します。
また、「全件表示」ボタンを押すと全てのデータを表示できます。

ソースコード

app.py
import tkinter as tk
from tkinter import ttk

import repository


# 社員を名前で検索して、表示する
def search_employee_by_name():
    name = entry_search_name.get()

    # 既存のデータを削除
    for item in tree.get_children():
        tree.delete(item)

    # DBから検索
    rows = repository.get_employee_by_name(name)

    # Treeviewに結果を追加
    for row in rows:
        tree.insert("", tk.END, values=row)


# 全社員を表示する
def load_all_employee():
    # 既存のデータを削除
    for item in tree.get_children():
        tree.delete(item)

    rows = repository.get_employee_all()

    for row in rows:
        tree.insert("", tk.END, values=row)


def main():
    global tree
    global entry_search_name

    root = tk.Tk()
    root.title("DB管理ツール")

    # 検索エリア
    search_frame = ttk.LabelFrame(root, text="検索")
    search_frame.pack(fill=tk.X, padx=10, pady=10)

    ttk.Label(search_frame, text="名前").pack(side=tk.LEFT, padx=5)

    entry_search_name = ttk.Entry(search_frame, width=30)
    entry_search_name.pack(side=tk.LEFT, padx=5)

    ttk.Button(
        search_frame,
        text="検索",
        command=search_employee_by_name,
    ).pack(side=tk.LEFT, padx=5)

    ttk.Button(
        search_frame,
        text="全件表示",
        command=load_all_employee,
    ).pack(side=tk.LEFT, padx=5)

    # 一覧表示エリア
    columns = (
        "id",
        "name",
        "department",
        "position",
        "salary",
        "hire_date",
    )

    tree = ttk.Treeview(
        root,
        columns=columns,
        show="headings",
        height=15,
    )

    tree.heading("id", text="ID")
    tree.heading("name", text="名前")
    tree.heading("department", text="部署")
    tree.heading("position", text="役職")
    tree.heading("salary", text="給与")
    tree.heading("hire_date", text="入社日")

    tree.column("id", width=50)
    tree.column("name", width=120)
    tree.column("department", width=100)
    tree.column("position", width=80)
    tree.column("salary", width=100)
    tree.column("hire_date", width=100)

    tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

    load_all_employee()

    root.mainloop()


if __name__ == "__main__":
    main()
repository.py
import sqlite3

DB_PATH = "sample.db"


def get_employee_all():
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        SELECT
            *
        FROM
            employees
        ORDER BY
            id
    """

    rows = cur.execute(sql).fetchall()

    conn.close()

    return rows


def get_employee_by_name(employee_name):
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        SELECT
            *
        FROM
            employees
        WHERE
            name LIKE :name
        ORDER BY
            id
    """

    params = {"name": f"%{employee_name}%"}

    rows = cur.execute(sql, params).fetchall()

    conn.close()

    return rows

実行画面

アプリケーション起動または、「全件表示」ボタンを押すと全件のデータが一覧に表示されました。

検索で名前を入れて「検索」ボタンを押したら、入力した文字列に部分一致するデータのみ一覧に表示されました。

  • 全件表示する画面
    image.png

  • 名前を検索した画面(検索結果が1件)
    image.png

  • 名前を検索した画面(検索結果が複数件)
    image.png

2. データの追加

データ追加機能を作成します。
各項目に値を入力して「追加」ボタンを押すと、入力したデータがDBに登録され、一覧に反映されます。

ソースコード

app.py
import tkinter as tk
from tkinter import ttk

import repository


# 社員を名前で検索して、表示する
def search_employee_by_name():
    # 既存コードは省略


# 全社員を表示する
def load_all_employee():
    # 既存コードは省略


# 追加
# 社員情報を追加する
def add_employee():
    # 入力された社員情報を追加
    repository.insert_employee(
        entry_operation_name.get(),
        entry_operation_department.get(),
        entry_operation_position.get(),
        int(entry_operation_salary.get()),
        entry_operation_hire_date.get(),
    )

    # 一覧を再読込
    load_all_employee()

    # 入力欄をクリア
    entry_operation_name.delete(0, tk.END)
    entry_operation_department.delete(0, tk.END)
    entry_operation_position.delete(0, tk.END)
    entry_operation_salary.delete(0, tk.END)
    entry_operation_hire_date.delete(0, tk.END)


def main():
    # 既存コードは省略
    
    global entry_operation_name  # 追加
    global entry_operation_department  # 追加
    global entry_operation_position  # 追加
    global entry_operation_salary  # 追加
    global entry_operation_hire_date  # 追加

    # 既存コードは省略

    # 追加
    # データ操作エリア
    data_operation_frame = ttk.LabelFrame(root, text="データ操作")
    data_operation_frame.pack(fill=tk.X, padx=10, pady=10)

    ttk.Label(data_operation_frame, text="名前").grid(row=0, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="部署").grid(row=1, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="役職").grid(row=2, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="給与").grid(row=3, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="入社日").grid(row=4, column=0, padx=5, pady=5)

    entry_operation_name = ttk.Entry(data_operation_frame, width=20)
    entry_operation_name.grid(row=0, column=1, padx=5, pady=5)

    entry_operation_department = ttk.Entry(data_operation_frame, width=20)
    entry_operation_department.grid(row=1, column=1, padx=5, pady=5)

    entry_operation_position = ttk.Entry(data_operation_frame, width=20)
    entry_operation_position.grid(row=2, column=1, padx=5, pady=5)

    entry_operation_salary = ttk.Entry(data_operation_frame, width=20)
    entry_operation_salary.grid(row=3, column=1, padx=5, pady=5)

    entry_operation_hire_date = ttk.Entry(data_operation_frame, width=20)
    entry_operation_hire_date.grid(row=4, column=1, padx=5, pady=5)

    # 処理ボタンエリア
    button_frame = ttk.Frame(data_operation_frame)
    button_frame.grid(
        row=5,
        column=0,
        columnspan=2,
        pady=10,
    )

    ttk.Button(
        button_frame,
        text="追加",
        command=add_employee,
    ).pack(side=tk.LEFT, padx=5)

    load_all_employee()

    root.mainloop()


if __name__ == "__main__":
    main()
repository.py
import sqlite3

DB_PATH = "sample.db"

# 既存コードは省略

# 追加
def insert_employee(
    employee_name,
    department,
    position,
    salary,
    hire_date,
):
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        INSERT INTO
            employees (
                name,
                department,
                position,
                salary,
                hire_date
            )
        VALUES (
            :name,
            :department,
            :position,
            :salary,
            :hire_date
        )
    """

    params = {
        "name": employee_name,
        "department": department,
        "position": position,
        "salary": salary,
        "hire_date": hire_date,
    }

    cur.execute(sql, params)

    conn.commit()
    conn.close()

実行画面

「データ操作」で各項目に値を入力後、「追加」ボタンを押すとDBにデータが登録され、一覧に追加したデータが表示されました。

  • 入力前の画面
    image.png

  • 各項目の値を入力した画面
    image.png

  • 「追加」ボタンを押した後の画面
    image.png

3. データの更新

データ更新機能を作成します。
一覧から更新したいデータを選択すると、選択したデータの内容が入力欄に反映されます。入力欄の内容を編集することで既存データを更新できます。
「更新」ボタンを押すと、入力した値でデータが更新され、更新後の内容が一覧に表示されます。

ソースコード

app.py
import tkinter as tk
from tkinter import ttk

import repository


# 社員を名前で検索して、表示する
def search_employee_by_name():
    # 既存コードは省略


# 全社員を表示する
def load_all_employee():
    # 既存コードは省略


# 社員情報を追加する
def add_employee():
    # 既存コードは省略


# 追加
# 選択した社員情報を入力欄に表示する
def select_employee(event):
    selected = tree.focus()

    if not selected:
        return

    values = tree.item(selected, "values")

    entry_employee_id.delete(0, tk.END)
    entry_employee_id.insert(0, values[0])

    entry_operation_name.delete(0, tk.END)
    entry_operation_name.insert(0, values[1])

    entry_operation_department.delete(0, tk.END)
    entry_operation_department.insert(0, values[2])

    entry_operation_position.delete(0, tk.END)
    entry_operation_position.insert(0, values[3])

    entry_operation_salary.delete(0, tk.END)
    entry_operation_salary.insert(0, values[4])

    entry_operation_hire_date.delete(0, tk.END)
    entry_operation_hire_date.insert(0, values[5])


# 追加
# 社員情報を更新する
def update_employee():
    # 入力された値で社員情報を更新
    repository.update_employee(
        int(entry_employee_id.get()),
        entry_operation_name.get(),
        entry_operation_department.get(),
        entry_operation_position.get(),
        int(entry_operation_salary.get()),
        entry_operation_hire_date.get(),
    )

    # 一覧を再読込
    load_all_employee()

    # 入力欄をクリア
    entry_employee_id.delete(0, tk.END)
    entry_operation_name.delete(0, tk.END)
    entry_operation_department.delete(0, tk.END)
    entry_operation_position.delete(0, tk.END)
    entry_operation_salary.delete(0, tk.END)
    entry_operation_hire_date.delete(0, tk.END)


def main():
    # 既存コードは省略
    
    global entry_employee_id # 追加
    
    # 既存コードは省略

    tree = ttk.Treeview(
        root,
        columns=columns,
        show="headings",
        height=15,
    )

    # 追加
    tree.bind("<<TreeviewSelect>>", select_employee)

    # 既存コードは省略

    # データ操作エリア
    data_operation_frame = ttk.LabelFrame(root, text="データ操作")
    data_operation_frame.pack(fill=tk.X, padx=10, pady=10)

    # 追加
    ttk.Label(data_operation_frame, text="ID").grid(row=0, column=0, padx=5, pady=5)
    # 以下はrowを修正
    ttk.Label(data_operation_frame, text="名前").grid(row=1, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="部署").grid(row=2, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="役職").grid(row=3, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="給与").grid(row=4, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="入社日").grid(row=5, column=0, padx=5, pady=5)

    # 追加
    entry_employee_id = ttk.Entry(data_operation_frame, width=20)
    entry_employee_id.grid(row=0, column=1, padx=5, pady=5)

    # 以下はrowを修正
    entry_operation_name = ttk.Entry(data_operation_frame, width=20)
    entry_operation_name.grid(row=1, column=1, padx=5, pady=5)

    entry_operation_department = ttk.Entry(data_operation_frame, width=20)
    entry_operation_department.grid(row=2, column=1, padx=5, pady=5)

    entry_operation_position = ttk.Entry(data_operation_frame, width=20)
    entry_operation_position.grid(row=3, column=1, padx=5, pady=5)

    entry_operation_salary = ttk.Entry(data_operation_frame, width=20)
    entry_operation_salary.grid(row=4, column=1, padx=5, pady=5)

    entry_operation_hire_date = ttk.Entry(data_operation_frame, width=20)
    entry_operation_hire_date.grid(row=5, column=1, padx=5, pady=5)

    # 処理ボタンエリア
    button_frame = ttk.Frame(data_operation_frame)
    # 以下はrowを修正
    button_frame.grid(
        row=6,
        column=0,
        columnspan=2,
        pady=10,
    )

    # 既存コードは省略

    # 追加
    ttk.Button(
        button_frame,
        text="更新",
        command=update_employee,
    ).pack(side=tk.LEFT, padx=5)

    load_all_employee()

    root.mainloop()


if __name__ == "__main__":
    main()
repository.py
import sqlite3

DB_PATH = "sample.db"

# 既存コードは省略

def update_employee(
    employee_id,
    employee_name,
    department,
    position,
    salary,
    hire_date,
):
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        UPDATE
            employees
        SET
            name = :name,
            department = :department,
            position = :position,
            salary = :salary,
            hire_date = :hire_date
        WHERE
            id = :id
    """

    params = {
        "id": employee_id,
        "name": employee_name,
        "department": department,
        "position": position,
        "salary": salary,
        "hire_date": hire_date,
    }

    cur.execute(sql, params)

    conn.commit()
    conn.close()

実行画面

一覧からデータを選択すると選択したデータの値が入力欄に反映されました。
入力欄の値を修正して、「更新」ボタンを押すとDBにデータが更新され、一覧に更新したデータが表示されました。

  • 入力前の画面
    image.png

  • 一覧からデータを選択した画面
    image.png

  • 入力欄のデータを編集した画面(部署と給与を修正)
    image.png

  • 「更新」ボタンを押した後の画面
    image.png

4. データの削除

データ削除機能を作成します。
一覧から削除したいデータを選択して「削除」ボタンを押すと、選択したデータがDBから削除されます。
削除後は一覧が再表示され、削除したデータが表示されなくなります。

ソースコード

app.py
import tkinter as tk
from tkinter import ttk

import repository


# 社員を名前で検索して、表示する
def search_employee_by_name():
    # 既存コードは省略


# 全社員を表示する
def load_all_employee():
    # 既存コードは省略


# 社員情報を追加する
def add_employee():
    # 既存コードは省略


# 選択した社員情報を入力欄に表示する
def select_employee(event):
    # 既存コードは省略


# 社員情報を更新する
def update_employee():
    # 既存コードは省略


# 追加
# 社員情報を削除する
def delete_employee():
    employee_id = entry_employee_id.get()

    if not employee_id:
        return

    # 入力されたIDで社員情報を削除
    repository.delete_employee(int(employee_id))

    # 一覧を再読込
    load_all_employee()

    # 入力欄をクリア
    entry_employee_id.delete(0, tk.END)
    entry_operation_name.delete(0, tk.END)
    entry_operation_department.delete(0, tk.END)
    entry_operation_position.delete(0, tk.END)
    entry_operation_salary.delete(0, tk.END)
    entry_operation_hire_date.delete(0, tk.END)


def main():
    # 既存コードは省略

    # 処理ボタンエリア
    button_frame = ttk.Frame(data_operation_frame)
    button_frame.grid(
        row=6,
        column=0,
        columnspan=2,
        pady=10,
    )

    ttk.Button(
        button_frame,
        text="追加",
        command=add_employee,
    ).pack(side=tk.LEFT, padx=5)

    ttk.Button(
        button_frame,
        text="更新",
        command=update_employee,
    ).pack(side=tk.LEFT, padx=5)

    # 追加
    ttk.Button(
        button_frame,
        text="削除",
        command=delete_employee,
    ).pack(side=tk.LEFT, padx=5)

    load_all_employee()

    root.mainloop()


if __name__ == "__main__":
    main()
repository.py
import sqlite3

DB_PATH = "sample.db"

# 既存コードは省略

# 追加
def delete_employee(employee_id):
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        DELETE FROM
            employees
        WHERE
            id = :id
    """

    params = {
        "id": employee_id,
    }

    cur.execute(sql, params)

    conn.commit()
    conn.close()

実行画面

一覧から削除したいデータを選択すると、削除したいデータが選択されました。
「削除」ボタンを押すと、選択したデータがDBから削除され、一覧からも削除されました。

  • 入力前の画面
    image.png

  • 一覧からデータを選択した画面
    image.png

  • 「削除」ボタンを押した後の画面
    image.png

完成したコード

今まで作成したコードをまとめると以下のようになります。

app.py
import tkinter as tk
from tkinter import ttk

import repository


# 社員を名前で検索して、表示する
def search_employee_by_name():
    name = entry_search_name.get()

    # 既存のデータを削除
    for item in tree.get_children():
        tree.delete(item)

    # DBから検索
    rows = repository.get_employee_by_name(name)

    # Treeviewに結果を追加
    for row in rows:
        tree.insert("", tk.END, values=row)


# 全社員を表示する
def load_all_employee():
    # 既存のデータを削除
    for item in tree.get_children():
        tree.delete(item)

    rows = repository.get_employee_all()

    for row in rows:
        tree.insert("", tk.END, values=row)


# 社員情報を追加する
def add_employee():
    # 入力された社員情報を追加
    repository.insert_employee(
        entry_operation_name.get(),
        entry_operation_department.get(),
        entry_operation_position.get(),
        int(entry_operation_salary.get()),
        entry_operation_hire_date.get(),
    )

    # 一覧を再読込
    load_all_employee()

    # 入力欄をクリア
    entry_operation_name.delete(0, tk.END)
    entry_operation_department.delete(0, tk.END)
    entry_operation_position.delete(0, tk.END)
    entry_operation_salary.delete(0, tk.END)
    entry_operation_hire_date.delete(0, tk.END)


# 選択した社員情報を入力欄に表示する
def select_employee(event):
    selected = tree.focus()

    if not selected:
        return

    values = tree.item(selected, "values")

    entry_employee_id.delete(0, tk.END)
    entry_employee_id.insert(0, values[0])

    entry_operation_name.delete(0, tk.END)
    entry_operation_name.insert(0, values[1])

    entry_operation_department.delete(0, tk.END)
    entry_operation_department.insert(0, values[2])

    entry_operation_position.delete(0, tk.END)
    entry_operation_position.insert(0, values[3])

    entry_operation_salary.delete(0, tk.END)
    entry_operation_salary.insert(0, values[4])

    entry_operation_hire_date.delete(0, tk.END)
    entry_operation_hire_date.insert(0, values[5])


# 社員情報を更新する
def update_employee():
    # 入力された値で社員情報を更新
    repository.update_employee(
        int(entry_employee_id.get()),
        entry_operation_name.get(),
        entry_operation_department.get(),
        entry_operation_position.get(),
        int(entry_operation_salary.get()),
        entry_operation_hire_date.get(),
    )

    # 一覧を再読込
    load_all_employee()

    # 入力欄をクリア
    entry_employee_id.delete(0, tk.END)
    entry_operation_name.delete(0, tk.END)
    entry_operation_department.delete(0, tk.END)
    entry_operation_position.delete(0, tk.END)
    entry_operation_salary.delete(0, tk.END)
    entry_operation_hire_date.delete(0, tk.END)


# 社員情報を削除する
def delete_employee():
    employee_id = entry_employee_id.get()

    if not employee_id:
        return

    # 入力されたIDで社員情報を削除
    repository.delete_employee(int(employee_id))

    # 一覧を再読込
    load_all_employee()

    # 入力欄をクリア
    entry_employee_id.delete(0, tk.END)
    entry_operation_name.delete(0, tk.END)
    entry_operation_department.delete(0, tk.END)
    entry_operation_position.delete(0, tk.END)
    entry_operation_salary.delete(0, tk.END)
    entry_operation_hire_date.delete(0, tk.END)


def main():
    global tree
    global entry_search_name
    global entry_employee_id
    global entry_operation_name
    global entry_operation_department
    global entry_operation_position
    global entry_operation_salary
    global entry_operation_hire_date

    root = tk.Tk()
    root.title("DB管理ツール")

    # 検索エリア
    search_frame = ttk.LabelFrame(root, text="検索")
    search_frame.pack(fill=tk.X, padx=10, pady=10)

    ttk.Label(search_frame, text="名前").pack(side=tk.LEFT, padx=5)

    entry_search_name = ttk.Entry(search_frame, width=30)
    entry_search_name.pack(side=tk.LEFT, padx=5)

    ttk.Button(
        search_frame,
        text="検索",
        command=search_employee_by_name,
    ).pack(side=tk.LEFT, padx=5)

    ttk.Button(
        search_frame,
        text="全件表示",
        command=load_all_employee,
    ).pack(side=tk.LEFT, padx=5)

    # 一覧表示エリア
    columns = (
        "id",
        "name",
        "department",
        "position",
        "salary",
        "hire_date",
    )

    tree = ttk.Treeview(
        root,
        columns=columns,
        show="headings",
        height=15,
    )

    tree.bind("<<TreeviewSelect>>", select_employee)

    tree.heading("id", text="ID")
    tree.heading("name", text="名前")
    tree.heading("department", text="部署")
    tree.heading("position", text="役職")
    tree.heading("salary", text="給与")
    tree.heading("hire_date", text="入社日")

    tree.column("id", width=50)
    tree.column("name", width=120)
    tree.column("department", width=100)
    tree.column("position", width=80)
    tree.column("salary", width=100)
    tree.column("hire_date", width=100)

    tree.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)

    # データ操作エリア
    data_operation_frame = ttk.LabelFrame(root, text="データ操作")
    data_operation_frame.pack(fill=tk.X, padx=10, pady=10)

    ttk.Label(data_operation_frame, text="ID").grid(row=0, column=0, padx=5, pady=5)

    ttk.Label(data_operation_frame, text="名前").grid(row=1, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="部署").grid(row=2, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="役職").grid(row=3, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="給与").grid(row=4, column=0, padx=5, pady=5)
    ttk.Label(data_operation_frame, text="入社日").grid(row=5, column=0, padx=5, pady=5)

    entry_employee_id = ttk.Entry(data_operation_frame, width=20)
    entry_employee_id.grid(row=0, column=1, padx=5, pady=5)

    entry_operation_name = ttk.Entry(data_operation_frame, width=20)
    entry_operation_name.grid(row=1, column=1, padx=5, pady=5)

    entry_operation_department = ttk.Entry(data_operation_frame, width=20)
    entry_operation_department.grid(row=2, column=1, padx=5, pady=5)

    entry_operation_position = ttk.Entry(data_operation_frame, width=20)
    entry_operation_position.grid(row=3, column=1, padx=5, pady=5)

    entry_operation_salary = ttk.Entry(data_operation_frame, width=20)
    entry_operation_salary.grid(row=4, column=1, padx=5, pady=5)

    entry_operation_hire_date = ttk.Entry(data_operation_frame, width=20)
    entry_operation_hire_date.grid(row=5, column=1, padx=5, pady=5)

    # 処理ボタンエリア
    button_frame = ttk.Frame(data_operation_frame)
    button_frame.grid(
        row=6,
        column=0,
        columnspan=2,
        pady=10,
    )

    ttk.Button(
        button_frame,
        text="追加",
        command=add_employee,
    ).pack(side=tk.LEFT, padx=5)

    ttk.Button(
        button_frame,
        text="更新",
        command=update_employee,
    ).pack(side=tk.LEFT, padx=5)

    ttk.Button(
        button_frame,
        text="削除",
        command=delete_employee,
    ).pack(side=tk.LEFT, padx=5)

    load_all_employee()

    root.mainloop()


if __name__ == "__main__":
    main()
repository.py
import sqlite3

DB_PATH = "sample.db"


def get_employee_all():
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        SELECT
            *
        FROM
            employees
        ORDER BY
            id
    """

    rows = cur.execute(sql).fetchall()

    conn.close()

    return rows


def get_employee_by_name(employee_name):
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        SELECT
            *
        FROM
            employees
        WHERE
            name LIKE :name
        ORDER BY
            id
    """

    params = {"name": f"%{employee_name}%"}

    rows = cur.execute(sql, params).fetchall()

    conn.close()

    return rows


def insert_employee(
    employee_name,
    department,
    position,
    salary,
    hire_date,
):
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        INSERT INTO
            employees (
                name,
                department,
                position,
                salary,
                hire_date
            )
        VALUES (
            :name,
            :department,
            :position,
            :salary,
            :hire_date
        )
    """

    params = {
        "name": employee_name,
        "department": department,
        "position": position,
        "salary": salary,
        "hire_date": hire_date,
    }

    cur.execute(sql, params)

    conn.commit()
    conn.close()


def update_employee(
    employee_id,
    employee_name,
    department,
    position,
    salary,
    hire_date,
):
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        UPDATE
            employees
        SET
            name = :name,
            department = :department,
            position = :position,
            salary = :salary,
            hire_date = :hire_date
        WHERE
            id = :id
    """

    params = {
        "id": employee_id,
        "name": employee_name,
        "department": department,
        "position": position,
        "salary": salary,
        "hire_date": hire_date,
    }

    cur.execute(sql, params)

    conn.commit()
    conn.close()


def delete_employee(employee_id):
    conn = sqlite3.connect(DB_PATH)
    cur = conn.cursor()

    sql = """
        DELETE FROM
            employees
        WHERE
            id = :id
    """

    params = {
        "id": employee_id,
    }

    cur.execute(sql, params)

    conn.commit()
    conn.close()

おわりに

Pythonの標準ライブラリであるTkinterを使用して、SQLiteを操作するGUIアプリケーションを作成しました。
今回作成したツールでは、GUI上からSQLiteに対する基本的なCRUD操作ができます。
ここで、入力値のチェック、例外処理などの実装や検索条件追加、ソート機能、ページングなどの機能を追加実装することでよりツールを発展させることもできます。
また、今回はSQLiteを使用しましたが、「repository.py」を各DBに合わせて実装することで、MySQLやPostgreSQLなど他のデータベースにも対応できると思います。
最後に、Tkinterは手軽にGUIアプリケーションの作成ができるので、今回のようなDB操作だけではなく、色々な目的のアプリケーション開発に活用できると思います。
今回の記事が、Tkinterを利用したGUIアプリケーション開発やデータベース操作ツール作成の参考になれば幸いです。

参考

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?