アプリケーションの基本構造CRUDをPython+tkinter環境にてサンプルを見ながら解説

Python

データを扱うアプリケーションにはCRUD(クラッド)という基本構造があります。
このCRUDを知っておくと、全てのアプリケーションに応用が効きます。
この記事ではそんなCRUDについて、前編後編に分けて解説します。

CRUDとは?

CRUDとは、

  • Creste(登録)
  • Read(表示)
  • Update(更新)
  • Delete(削除)

の頭文字を取ったものです。

どんなデータでも、
「登録」して、
「表示」して、
「更新」して、
「削除」することによってアプリケーションは成り立っています。

違いはデータがどこにあるのか(データベースにあるのか、ファイルでもっているのか、etc.)、表示する方法は何か(Webシステムなのか、GUIアプリなのか、etc.)、などの違いだけです。

だから、このCRUDをそれぞれ作りこむことで、アプリケーションは基本成り立つのです。
そこに、保存機能やログイン機能などを付ければ、アプリケーションの完成です。

サンプルで見るCRUD

それでは、CRUDのサンプルを示します。
今回はPython+tkinterで書きます。tkinterの説明は割愛します。

このアプリケーションは、一行のテキストを入力して、それを一覧で表示するものです。保存機能などはついていません。
なお、エラーチェックも最小限ですので、そこは適宜お読み替えください。

まず、アプリケーションの基本構造を示します。

import tkinter as tk
import tkinter.ttk as ttk

class Application(tk.Frame):

    def __init__(self,master):
        super().__init__(master)
        self.data = []
        self.master = master
        self.master.title("CRUDサンプル")
        self.num = []
        self.text = []

        button = tk.Button(self.master, text='追加', command=self.create)
        button.grid(row=0, column=0)

        self.row_val = tk.IntVar(self.master)
        row = ttk.Entry(self.master, textvariable=self.row_val)
        row.grid(row=0, column=1)

        button = tk.Button(self.master, text='を更新', command=self.update)
        button.grid(row=0, column=2)

        button = tk.Button(self.master, text='を削除', command=self.delete)
        button.grid(row=0, column=3)

    def create(self):
        ・・・
    def update(self):
        ・・・
    def delete(self):
        ・・・
    def show(self):
        ・・・

win = tk.Tk()
app = Application(master=win)
app.mainloop()

初期画面

初期化関数ではウィジットを配置して、クラスのデータを準備しています。ここで、
data:テキストの配列
num:テキスト表示領域の行番号(Label)の配列
text:テキスト(Label)の配列
です。

Read(表示)

順番が逆になりますが、表示から見ていきましょう。

    def show(self):
        for num in self.num:
            num.destroy()
        for text in self.text:
            text.destroy()
        self.num = []
        self.text = []
        for i,d in enumerate(self.data):
            self.num.append(tk.Label(self.master, text=i+1))
            self.num[i].grid(row=i+2, column=0)
            self.text.append(tk.Label(self.master, text=d))
            self.text[i].grid(row=i+2, column=1, columnspan=3)

まず今表示されている行番号とテキストのウィジットを壊します。全て消します。
その後で、self.dataの一つ一つを行番号と共に表示していきます。

Create(登録)

次に登録です。

    def create(self):

        class NewEntry(tk.Frame):

            def __init__(self, master, parent):
                super().__init__(master)
                self.master = master
                self.parent = parent

                self.master.title("CREATE")

                self.text_val = tk.StringVar(self.master)
                text = ttk.Entry(self.master, textvariable=self.text_val)
                text.grid(row=0, column=0)

                button = tk.Button(self.master, text='OK', command=self.ok)
                button.grid(row=1, column=0)

            def ok(self):
                self.parent.create2(self.text_val.get().strip())
                self.master.destroy()

        win = tk.Tk()
        app = NewEntry(master=win, parent=self)
        app.mainloop()

    def create2(self, new_str):
        self.data.append(new_str)
        self.show()

入力用ウィンドゥを出して、値をcreate2でもらっています。
create2ですることは、self.dataへのデータの追加と、表示をコールすることです。

例えば2行追加してみましょう。

登録画面

一行登録

二行登録

Update(変更)

変更は登録より少し長いです。

    def update(self):
        try:
            if self.row_val.get() < 1 or self.row_val.get() > len(self.data):
                return
        except:
            return

        class UpdateEntry(tk.Frame):

            def __init__(self, master, parent, old_str):
                super().__init__(master)
                self.master = master
                self.parent = parent

                self.master.title("UPDATE")

                self.text_val = tk.StringVar(self.master)
                self.text_val.set(old_str)
                text = ttk.Entry(self.master, textvariable=self.text_val)
                text.grid(row=0, column=0)

                button = tk.Button(self.master, text='OK', command=self.ok)
                button.grid(row=1, column=0)

            def ok(self):
                self.parent.update2(self.text_val.get().strip())
                self.master.destroy()

        win = tk.Tk()
        app = UpdateEntry(master=win, parent=self, old_str=self.data[self.row_val.get()-1])
        app.mainloop()
        
    def update2(self, new_str):
        self.data[self.row_val.get()-1] = new_str
        self.show()

行数のチェックと、入力画面に初期値を渡すところが登録との違いです。
update2で入力画面から変更後の値をもらって、dataの該当する行数のところを書き換え、表示を呼んでいます。

例えば2行目を書き換えてみましょう。

変更画面
二行目変更

Delete(削除)

削除は簡単です。

    def delete(self):
        try:
            if self.row_val.get() < 1 or self.row_val.get() > len(self.data):
                return
        except:
            return

        del self.data[self.row_val.get()-1]
        self.show()

まず行数のチェックをして、その後でdataの該当する要素を削除して、表示を呼ぶだけです。

1行目を削除してみます。

ここで、プログラムの全体を再掲します。

import tkinter as tk
import tkinter.ttk as ttk

class Application(tk.Frame):

    def __init__(self,master):
        super().__init__(master)
        self.data = []
        self.master = master
        self.master.title("CRUDサンプル")
        self.num = []
        self.text = []

        button = tk.Button(self.master, text='追加', command=self.create)
        button.grid(row=0, column=0)

        self.row_val = tk.IntVar(self.master)
        row = ttk.Entry(self.master, textvariable=self.row_val)
        row.grid(row=0, column=1)

        button = tk.Button(self.master, text='を更新', command=self.update)
        button.grid(row=0, column=2)

        button = tk.Button(self.master, text='を削除', command=self.delete)
        button.grid(row=0, column=3)

    def create(self):

        class NewEntry(tk.Frame):

            def __init__(self, master, parent):
                super().__init__(master)
                self.master = master
                self.parent = parent

                self.master.title("CREATE")

                self.text_val = tk.StringVar(self.master)
                text = ttk.Entry(self.master, textvariable=self.text_val)
                text.grid(row=0, column=0)

                button = tk.Button(self.master, text='OK', command=self.ok)
                button.grid(row=1, column=0)

            def ok(self):
                self.parent.create2(self.text_val.get().strip())
                self.master.destroy()

        win = tk.Tk()
        app = NewEntry(master=win, parent=self)
        app.mainloop()

    def create2(self, new_str):
        self.data.append(new_str)
        self.show()

    def update(self):
        try:
            if self.row_val.get() < 1 or self.row_val.get() > len(self.data):
                return
        except:
            return

        class UpdateEntry(tk.Frame):

            def __init__(self, master, parent, old_str):
                super().__init__(master)
                self.master = master
                self.parent = parent

                self.master.title("UPDATE")

                self.text_val = tk.StringVar(self.master)
                self.text_val.set(old_str)
                text = ttk.Entry(self.master, textvariable=self.text_val)
                text.grid(row=0, column=0)

                button = tk.Button(self.master, text='OK', command=self.ok)
                button.grid(row=1, column=0)

            def ok(self):
                self.parent.update2(self.text_val.get().strip())
                self.master.destroy()

        win = tk.Tk()
        app = UpdateEntry(master=win, parent=self, old_str=self.data[self.row_val.get()-1])
        app.mainloop()
        
    def update2(self, new_str):
        self.data[self.row_val.get()-1] = new_str
        self.show()

    def delete(self):
        try:
            if self.row_val.get() < 1 or self.row_val.get() > len(self.data):
                return
        except:
            return

        del self.data[self.row_val.get()-1]
        self.show()

    def show(self):
        for num in self.num:
            num.destroy()
        for text in self.text:
            text.destroy()
        self.num = []
        self.text = []
        for i,d in enumerate(self.data):
            self.num.append(tk.Label(self.master, text=i+1))
            self.num[i].grid(row=i+2, column=0)
            self.text.append(tk.Label(self.master, text=d))
            self.text[i].grid(row=i+2, column=1, columnspan=3)

win = tk.Tk()
app = Application(master=win)
app.mainloop()

まとめ・アプリケーションはCRUDを拡張したもの

この記事ではCRUDについて解説しました。
繰り返しになりますが、どんなアプリケーションでもCRUDを拡張したものです。このサイクルが分かっていればデータを扱うことができます。
今回のサンプルプログラムを、データベースにアクセスするものにしたり、Flaskのアプリケーションにアレンジしてみたりしてください。それは立派なデータベースシステムですし、Webシステムです。
アプリケーションがやっていることは、複雑そうに見えて基本構造は単純です。
あとはどれくらい応用の幅が広がるかにかかってきます。スキルは常に磨きましょう。

エージェントへの登録はお済みですか?

今すぐフリーランスになる気がなくても、エージェントへの登録は済ませておくことをお勧めします。理由はストレスや疲労が限界に達してからだと遅いから。

現在の自身のフリーランスとしての価値・単価相場を把握できますし、条件にあった案件をキャッチできるようになるので、いざフリーランスになろうとした際に早期に手が打てます。

エージェント登録は無料なので、今はフリーランスにならなくとも登録だけはしておくべきです。

真っ先に登録すべきエージェントは、圧倒的な営業力を持ち多くのクライアントを開拓しているDYMテック。2500社の優良な取引先と条件交渉力の強いエージェントです。

また、案件紹介のみでなく、エンジニアとしてのキャリア相談や業界動向のキャッチアップなど、フリーランス対してのサポートも充実していますので、初めてフリーランスに挑戦する方も安心です。

DYMテックに登録する

フリーランスエンジニア向けエージェントおすすめ7社

Python
shigotoswitchをフォローする
しごとスイッチ