以下のGIFアニメは、今回作成したアプリをデバッグ実行しているところだ。
見ると分かる通り、[submit]ボタンによる項目の追加、[done!]リンクによる完了状態の変更、[delete all done items]ボタンによる完了した項目の削除はうまくいっている。しかし、[delete]リンクをクリックしても項目が削除されないようだ。
[delete]リンクをクリックしたときには、「/deleteitem/XX」URLがリクエストされる(XXは項目のID)。実際に呼び出されるビュー関数は「delete_todoitem」だ。そして、最終的にはToDoListクラスのdeleteメソッドが呼び出される。
そこで、まずtodo.pyファイルにあるdeleteメソッドを次のように変更する。pass文は「何もしない文」だが、ここではdel文での要素の削除がうまくいっていることを確認するために記述してある。
def delete(self, item_id):
item = [x for x in self.todolist if x.item_id == item_id]
del item[0]
pass
そして、app.pyファイルのdelete_todoitem関数にブレークポイントを設定して、動作を確認してみよう。
何か項目を入力して、[submit]ボタンをクリックし、ToDoリストに項目を追加したところで、[delete]リンクをクリックしてみよう。
これにより、デバッグ実行が中断される。
デバッグ用のツールバーで[ステップ インする]ボタンをクリックすると、先ほどコードを修正したToDoListクラスのdeleteメソッドに制御が移る。
ここで[デバッグ]ビューの[変数]ペーンを展開しておこう。ここにはローカル変数やパラメーター、インスタンスのメンバなどが一覧されている。
この状態では、self.todolistに追加した項目が存在し、ローカル変数のitemは未定義だ。ここではリストの内包表記を使って、リスト内から特定の要素を検索している。「x for x in self.todolist」に続く「if x.item_id == item_id」でメソッドに渡されたIDと各要素のitem_idメンバの値を比較するようにしているので、実際に取得するのは常に1つの要素で構成されるリストとなる(そのため、「del item[0]」として要素を削除している)。この辺の値の移り変わりに注意しながら、[ステップ インする]ボタンを何度かクリックし、pass文まで実行を進めてみる。
[デバッグ]ビューで変数を展開して一覧表示してみると分かるが、「del item[0]」でローカル変数itemは空のリストになるが、そもそもの削除対象のself.todolistからは要素が削除されていない。これは、一時的に作成したリストの要素からToDoItemインスタンスへの参照を削除しただけで、self.todolistにはその参照が残されたままということだ。つまり、削除できていない。
どうしようか考えたのだが、ここでは次のようにdeleteメソッドを変更することにした。
def delete(self, item_id):
self.todolist = [x for x in self.todolist if x.item_id != item_id]
# delとpassの行は削除する
これは何をしているのかというと、「指定されたIDではない要素で構成される」(指定されたIDの要素が削除された)リストをself.todolistに代入している。デバッグ実行を中止して、上のようにコードを修正してから、(ブレークポイントを解除して)デバッグ実行をしているところを以下に示す。
今回はデータベースなどを使わずに、独自クラスを作成して、そこで項目を管理する形のToDoリストアプリを作成した。次回は、データベースを利用したものに、これを書き換えてみよう。なお、今回の記事ではGitHubで公開されている「flask-simple-todo」を参考にさせていただいている。ライセンス表記はこちら。
Copyright© Digital Advantage Corp. All Rights Reserved.