FlaskとSQLAlchemyで読書記録Webアプリを作る(4)
前回に続いて、読書記録Webアプリを作って行きましょう。
前回は読書記録データの作成、読み出しを行いましたので、今回は読書記録データの更新、削除とCRUD操作を網羅したいと思います。CRUDとは、Create(データの新規作成)、Read(データの読み込み)、Update(データの更新)、Delete(データの削除)のことです。これらを網羅すれば一通りの機能を作成できます。
Create(読書記録データの作成機能)
前回作成したものですが、念のため、再度記載します。
# web/views.py from web import app, db from web.forms import BookForm from web.models import Book from flask import render_template, redirect, url_for @app.route('/register', methods=['GET','POST']) def register_book(): form = BookForm() if form.validate_on_submit(): book = Book(title=form.title.data, author=form.author.data, genre=form.genre.data, date=form.date.data) db.session.add(book) db.session.commit() return redirect(url_for('index')) return render_template('register_book.html', form=form)
インポートしたBookFormクラスをインスタンス化します。validate_on_submitメソッドにより、POSTリクエスト(register_book.htmlへの入力)があり、かつ、その内容が有効かどうかをチェックします。
そうであれば、入力されたtitle, author, genre, dateをもとにBookオブジェクトを生成し、それをdb.session.add(book)
により、データベースにデータとして追加します。さらに、db.session.commit()
により、データベースへの登録を完了します。
そして、url_for('index')
により、index関数を発動するURLを取得し、そのURLにredirect
(遷移・移動)します。POSTリクエストがない、もしくは無効であれば、register_book.html
を表示します。
register_book.html
は以下の通りです。
# web/templates/register_book.html {% extends "base.html" %} {% block content %} <div class="container"> <form class="form-group" method="POST"> {{ form.hidden_tag() }} <br> <div class="form-group"> {{ form.title.label(class="form-control-label") }} {{ form.title(class="form-control form-control-lg") }} </div> <div class="form-group"> {{ form.author.label(class="form-control-label") }} {{ form.author(class="form-control form-control-lg") }} </div> <div class="form-group"> {{ form.genre.label(class="form-control-label") }} {{ form.genre(class="form-control form-control-lg") }} </div> <div class="form-group"> {{ form.date.label(class="form-control-label") }} {{ form.date(class="form-control form-control-lg", placeholder="2019/5/1") }} </div> <div class="form-group"> {{form.submit(class="btn btn-primary")}} </div> </form> </div> {% endblock %}
Read(読書記録データの一覧機能)
データ作成機能により作成した読書記録を一覧表示させる機能です。 これも前回記載しましたが、そのまま再掲します。
# web/views.py from web import app, db from web.forms import BookForm from web.models import Book from flask import render_template, redirect, url_for @app.route('/') def index(): books = Book.query.all() return render_template('index.html', books=books)
しかし、books = Book.query.all()
だと、登録順に表示されてしまいます。一番最近に読んだ本が最上位に来るように修正しましょう。以下のようにorder_by(Book.date.desc())
を入れればOKです。desc()
はdescening、即ち「降順」を表しています。「昇順」にしたい場合にはasc()
にします。
books = Book.query.order_by(Book.date.desc()).all()
@app.route('/') def index(): books = Book.query.order_by(Book.date.desc()).all() return render_template('index.html', books=books)
render_template
はtemplates
フォルダ下にあるindex.html
を表示します。その際にbooks
を一緒にindex.html
に渡します。books
は、Bookオブジェクトのリストとなっています。
index.html
は以下の通りです。books
リストから一つ一つBookオブジェクトを取り出して、そのtitleやauthorといったプロパティを表示させます。
<!-- web/templates/index.html --> {% extends "base.html" %} {% block content %} <br> <table class="table"> <thead class="thead-light"> <tr> <th scope="col">書籍名</th> <th scope="col">著者</th> <th scope="col">ジャンル</th> <th scope="col">読了日</th> </tr> </thead> {% for book in books%} <tbody> <tr> <td> {{ book.title }} </td> <td> {{ book.author }} </td> <td> {{ book.genre }} </td> <td> {{ book.date }} </td> </tr> </tbody> {% endfor %} </table> {% endblock %}
Update(読書記録データの修正機能)
続いて、データを修正できるようにしましょう。 indexページの読書記録一覧において、書籍をクリックすると、読書記録の登録ページに飛ぶようにします。そこではクリックした書籍データが表示されていて、そのデータを修正して登録すると、修正できるようにします。
index.html
の書籍名が表示されている箇所<td> {{ book.title }} </td>
の{{ book.title }}
を <a href="#"> </a>
で挟みます。また、#
の箇所には{{url_for('update_book',id=book.id)}}
を入力します。
<td> <a href="{{url_for('update_book',id=book.id)}}">{{ book.title }} </a></td>
さて、view.pyを修正しましょう。
まず、request
を追加でインポートします。また、view.pyの最後に、以下の@app.route('/update/<int:id>')
以下を追加します。
# web/views.py from flask import render_template, redirect, url_for, request @app.route('/<int:id>/update', methods=['GET','POST']) def update_book(id): book = Book.query.get(id) form = BookForm() if form.validate_on_submit(): book.title = form.title.data book.author = form.author.data book.genre = form.genre.data book.date = form.date.data db.session.commit() return redirect(url_for('index')) elif request.method == 'GET': form.title.data = book.title form.author.data = book.author form.genre.data = book.genre form.date.data = book.date return render_template('each_book.html', form=form, id=id)
register_book.html
をコピーして、`each_book.html'を作っておきます。現時点では中身は全く同じで結構です(後ほど、削除機能の作成の際に修正します)。
ここで、python books.py
もしくは環境変数を設定しておいて、flask run
にて実行してみます。
書籍名が青くなっており、リンクが貼られました。前回とは読書記録データが多少ことなっておりますが、ご容赦ください。
一つ目の書籍名をクリックしてみます。
読書記録データが表示されました。書籍名に「よん」を加えて、登録ボタンを押してみます。
きちんと修正ができました。ここで、具体的に見ていきましょう。
ます、indexページにて、書籍名をクリックすると、update_book関数が呼び出されます。その際に idとして読書記録データのbook.idも渡されます。
なお、@app.route
内は、/<id>/update
でも問題ありません。通常、必ず整数を受け取るように制限したい場合が多く、その場合、<int:id>とします。そうすると、整数以外の値が渡された際にはエラーになります。
さて、book = Book.query.get(id)
により、データベースから、当該idに紐ついているデータが検索され、bookに渡されます。一方で、登録の際と同様に、BookFormをインスタンス化しておきます。
書籍名をクリックした際は、情報を取得するだけですのでrequest.methodはGET
になります。従って、elif
以下となり、bookが保持しているデータを項目毎にformに渡しています。その上で、register_book.html
を表示していますので、登録する際と同じ画面を利用していますが、データが表示されています。
そこで、データの一部を変更して、「登録」ボタン(Submit)を押下すると、今度は同じ関数のif
以下が適用され、formに保存されている修正後のデータが、該当するbookのプロパティに保存され、commitすることで修正が確定します。
Delete(読書記録データの削除機能)
最後に、データを削除する機能です。
これは、削除したいデータをBook.query.get(id)
にて呼び出して、当該データをdb.session.delete
にて削除し、最終db.session.commit()
で確定させます。そして、index
ページに戻ります。以下がスクリプトです。
@books.route('/book/<int:id>/delete', methods=['GET','POST']) def delete_book(id): book = Book.query.get(id) db.session.delete(book) db.session.commit() return redirect(url_for('index'))
そして、each_book.html
を修正します。以下の通り、<a>...</a>
タグを追加します。
<div class="form-group"> {{form.submit(class="btn btn-primary")}} <a class="btn btn-danger" href="{{ url_for('delete_book', id=id)}}">削除</a> </div>
以上です。それでは実行してみましょう。indexページにて「吾輩は猫である」をクリックします。
削除ボタンが追加されています。削除ボタンを押してみます。
無事削除ができました。
これでCRUD機能が実装できました。
今回のスクリプトを以下にv2
としてアップロードしておきましたので、参考にしてみてください。
アプリの機能としてはまだ不十分かと思いますので、次回以降バージョンアップを図っていきたいと思います。
例えば、著者を別画面で登録できるようにして、読書記録登録時には、そこから選択できるようにしたり、ペジネーション(読書記録が多くなってきた場合に1ページあたりの表示件数を制限)できるようにしたりしていきたいと思います。
今回はこれにて。