【Python tkinter】データベースsqlite3をGUIアプリと連携させる
2020.05.05 /
PythonのTkinterでGUIアプリケーションを作成するとき、データベースと連携させる場合があります。
データベースと連携させることにより、様々な機能を含んだアプリケーションを作成できます。
今回は数あるDBRMSの中から、sqlite3を使ったアプリケーション構築方法を解説していきます。
以下リンク(tkinterチュートリアル)で作成しているデスクトップアプリケーションとsqlite3を連携させます。
【Python】OUTLOOKの添付ファイルを指定フォルダに自動保存するアプリ開発
【Python tkinter】メニューバー(Menu)の作成方法
sqlite3とは
sqlite3はPythonの標準モジュールです。
そのためモジュールをインポートして、データベースに接続するだけで使えるようになります。
sqlite3で使用するデータベースは、その名の通りSQLiteです。
SQLiteはオープンソースのRDBMSです。
特徴としてWebサーバーを介せずに使用できるため、サーバープロセスを起動させることなく利用が可能です。
アプリケーションに組み込んで使用されるという、RDBMSとしては珍しい特徴を持っています。
sqlite3のデータベースを操作するためにはSQLという言語を使用します。
このSQLを使ってデータベースの追加やデータの取得などの操作を行います。
またsqlite3はMySQLなどのRDBMSと比べると機能面は乏しいですが、スピードが非常に速いので、大量のデータを扱うことが得意です。
RDBMS(Relational DataBase Management System)とは、リレーショナルデータベース(RDB)を管理するためのソフトウェアです。簡単に言うと、データベースを楽に操作するためのソフトです。
大規模なデータベースにはSQLiteは向いていないので、そういった場合はMySQLを使うのがお勧めです。
SQLiteは小規模のデータベースシステムで使うようにしましょう。
またSQLiteはファイル形式のため、セキュリティ機能は一切ないです。
データを守るためのセキュリティ対策は自身で行う必要があります。
sqlite3のデータ型
sqlite3のデータ型は以下のようになります。
データ型 | 説明 |
---|---|
INTEGER | 整数型 |
REAL | 小数型 |
TEXT | 文字列型 |
NULL | NULL |
追加するsqlite3のソースコード
「OUTLOOKから添付ファイルを保存するアプリ」に下記sqlite3を使用するためのコードを追加します。
import sqlite3
# データベースに接続または作成
dbname = "outlook.db"
connection = sqlite3.connect(dbname)
# カーソルの取得
c = connection.cursor()
# SQL文の実行
c.execute('CREATE TABLE IF NOT EXISTS default_folder (folder varchar(1024))')
c.execute('SELECT * FROM default_folder')
# 新しくDBを作成した場合、テーブルを作成する
if not c.fetchone():
folder = 'C:/'
c.execute("""
INSERT INTO default_folder values ('{}');
""".format(folder))
# データベースから値・文字列を取得
c.execute('SELECT * FROM default_folder')
default_folder = c.fetchone()
# データベースに変更を保存
connection.commit()
# データベースを閉じる
connection.close()
上記コードについて詳しく説明していきます。
sqlite3の使用手順
sqlite3を使用するためには、下記の流れを守る必要があります。
1: sqlite3をインポート
2: データベースに接続または作成
3: カーソルの取得
4: SQL文の実行
5: コミット
6: データベースとの接続切断
sqlite3の使用方法
sqlite3モジュールのインポート
import sqlite3
sqlite3はPythonの標準モジュールなので、使うためにインストールなどは必要なく、プログラムの頭にsqlite3をインポートするだけで使用できます。
sqlite3の接続・作成
# データベースに接続または作成
dbname = "outlook.db"
connection = sqlite3.connect(dbname)
データベースに接続またはデータベースの作成には,sqlite3.connect()メソッドを使用しConnectionオブジェクトを作成します。
Connectionオブジェクト作成時に、引数で渡されたデータベースがなければ自動で新しいデータベースを作成し、存在すれば接続を行います。
また引数に":memory:"を使うとRAM上にデータベースを作ることができます。
カーソルの取得
c = connection.cursor()
ConnectionオブジェクトからCursorオブジェクトを作成します。
これによりSQLを使ってデータベースに対して様々な命令を行えるようになります。
SQL文の実行
c.execute('CREATE TABLE IF NOT EXISTS default_folder (folder varchar(1024))')
c.execute('SELECT * FROM default_folder')
CursorオブジェクトのexecuteメソッドでSQL文を実行できます。
上記コードの1行目では、データベース内に対象テーブルがなかった場合、CREATE文でテーブルを作成しています。
つまり初めてこのプログラムを起動し、データベースが作成されたときのみテーブルが作成されることを意味します。
初回起動時にテーブルにデータを追加する
if not c.fetchone():
folder = 'C:/'
c.execute("""
INSERT INTO default_folder values ('{}');
""".format(folder))
初回起動時(テーブルが作成されたとき)はテーブルになにもデータが入っていないので、データを挿入しています。
if not c.fetchone()により、事前にselect文で取得していたデータの有無を確認しています。
【Python】変数に格納されている値・文字列の有無(NULL)を判定する方法
データがなければ、Insert文でCドライブのパスをデータベースに挿入しています。
データベースから値・文字列を取得
c.execute('SELECT * FROM default_folder')
default_folder = c.fetchone()
SELECT文で取得した値をfetchoneメソッドで変数に格納しています。
データベースから取得する値が複数の場合は、fetchallメソッドで取得します。
fetchoneメソッドやfetchallメソッドを実行し、レコードが何もない場合はNoneが返されます。
データベースに変更を保存
connection.commit()
データベースの変更を行ったら必ずコミットcommit()を行う必要があります。
コミットをせずにデータベースを閉じると、変更は保存されないので注意してください。
データベースを閉じる
connection.close()
データベースの作業を行いましたら、最後に必ずデータベースコネクションをcloseメソッドを使って閉じます。
あとはデータベースから取得した値を使いたい場所に入れ込みます。
entry_folder.insert(0, default_folder[0])
これによりアプリ起動時にデータベースから取得した値を初期値としてフォルダー名に入力されます。
まとめ
今回までで作成したアプリケーションの全コードを以下に記します。
# -*- coding: utf-8 -*-
"""
Created on Thu Apr 2 17:27:21 2020
@author: admin
"""
import win32com.client
import datetime
import os
import tkinter as tk
import tkinter.ttk as ttk
from tkinter import filedialog
from tkinter import messagebox
import os.path
import sqlite3
# データベースに接続または作成
dbname = "outlook.db"
connection = sqlite3.connect(dbname)
# カーソルの取得
c = connection.cursor()
# SQL文の実行
c.execute('CREATE TABLE IF NOT EXISTS default_folder (folder varchar(1024))')
c.execute('SELECT * FROM default_folder')
# 新しくDBを作成した場合、テーブルを作成する
if not c.fetchone():
folder = 'C:/'
c.execute("""
INSERT INTO default_folder values ('{}');
""".format(folder))
# データベースから値・文字列を取得
c.execute('SELECT * FROM default_folder')
default_folder = c.fetchone()
# データベースに変更を保存
connection.commit()
# データベースを閉じる
connection.close()
# 保存先フォルダーを指定し、entry_folderにセットする
def ask_folder():
fld = filedialog.askdirectory()
entry_folder.delete(0, tk.END)
entry_folder.insert(tk.END, fld)
def click_execute():
# Outlookからメール情報を取得
outlook = win32com.client.Dispatch("Outlook.Application").GetNamespace("MAPI")
if not entry_outlook.get():
# 受信フォルダのメールを取得
folders = outlook.GetDefaultFolder(6)
else:
# 指定されたメールフォルダのメールを取得
folders = outlook.GetDefaultFolder(6).Folders[entry_outlook.get()]
# メールフォルダ内のメールにアクセス
mails=folders.Items
#添付ファイルの保管用フォルダ作成
newfolder_path = entry_folder.get() + '/Outlook_test'
# 作成フォルダが存在するかの確認
if os.path.isdir(newfolder_path) == False:
# フォルダがなければ作成する
os.makedirs(newfolder_path)
# 絞り込み日程の取得
startdate = datetime.datetime.strptime(entry_start.get(), '%Y/%m/%d')
enddate = datetime.datetime.strptime(entry_end.get(), '%Y/%m/%d')
#メール情報を1件1件取得し、添付ファイルがあれば保存する
for mail in mails:
RT=mail.ReceivedTime
period = datetime.datetime(RT.year ,RT.month, RT.day, RT.hour, RT.minute, RT.second)
if startdate <= period <= enddate:
if mail.Attachments.Count > 0:
myDate = RT.strftime("%Y/%m/%d")
myDate = myDate.replace("/","-")
datefolder_path = newfolder_path + '\\' + myDate
if os.path.isdir(datefolder_path) == False:
os.makedirs(datefolder_path)
for myAttachment in mail.Attachments:
folder_path = datefolder_path + '\\' + myAttachment.FileName
if os.path.isfile(folder_path) == False:
myAttachment.SaveAsFile(folder_path)
messagebox.showinfo("完了","添付ファイルをダウンロードしました")
# メインウィンドウの設定
root = tk.Tk()
root.title("OUTLOOK操作")
root.geometry("600x300")
### menubarの作成と設置 ###
# menubarの大元(コンテナ)の作成と設置
menubar = tk.Menu(root)
root.config(menu=menubar)
# menubarを親として設定メニューを作成と表示
setting_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label='設定', menu=setting_menu)
# menubarを親としてヘルプメニューを作成と表示
help_menu = tk.Menu(menubar, tearoff=0)
menubar.add_cascade(label='ヘルプ', menu=help_menu)
# 設定メニューにプルダウンメニューを追加
setting_menu.add_command(label='環境設定')
setting_menu.add_command(label='終了')
# ヘルプメニューにプルダウンメニューを追加
help_menu.add_command(label='FAQ')
### menubarの終了 ###
# メインフレームの作成と設置
frame = ttk.Frame(root)
frame.grid(column=0, row=0, sticky=tk.NSEW, padx=5, pady=10)
# 各種ウィジェットの作成
label_start = ttk.Label(frame, text="集計開始日(yyyy/mm/dd):")
entry_start = ttk.Entry(frame)
label_end = ttk.Label(frame, text="集計終了日(yyyy/mm/dd):")
entry_end = ttk.Entry(frame)
label_folder = ttk.Label(frame, text="出力先フォルダ:")
entry_folder = ttk.Entry(frame, width=50)
button_folder = ttk.Button(frame, text="参照", command=ask_folder)
label_outlook = ttk.Label(frame, text="OUTLOOK受信フォルダ名:")
entry_outlook = ttk.Entry(frame)
button_execute = ttk.Button(frame, text="実行", command=click_execute)
# 各種ウィジェットの設置
label_start.grid(row=0, column=0, padx=10, pady=2)
entry_start.grid(row=0, column=1, sticky=tk.W)
label_end.grid(row=1, column=0, padx=10, pady=2)
entry_end.grid(row=1, column=1, sticky=tk.W)
label_folder.grid(row=2, column=0, padx=10,pady=2, sticky=tk.E)
entry_folder.grid(row=2, column=1,sticky=tk.W)
button_folder.grid(row=2, column=2, sticky=tk.E)
label_outlook.grid(row=3, column=0, padx=10, pady=2, sticky=tk.E)
entry_outlook.grid(row=3, column=1, sticky=tk.W)
button_execute.grid(row=4, column=1, pady=10)
# 初期値の入力
dt_now = datetime.datetime.now()
dt_now = dt_now.strftime("%Y/%m/%d")
entry_end.insert(tk.END, dt_now)
entry_folder.insert(0, default_folder[0])
root.mainloop()