Djangoで作った1行掲示板に投稿を編集・削除できる機能を追加してみましょう。編集フォームと投稿編集用のWebページ、編集内容をデータベースに保存する関数、データベースから投稿を削除する関数など複数の機能が必要になります。
目次
- 必要な機能のリストアップ
- ルーティング
- 投稿編集ページへ遷移するためのボタンをdetail.htmlに配置
- 投稿編集ページを呼び出すedit関数を作成
- 投稿編集ページのテンプレート(edit.html)の作成
- 編集内容をデータベースに保存するupdate関数を作成
- 投稿内容をデータベースから削除するdelete関数を作成
- 動作確認
必要な機能のリストアップ
まずはじめに必要になる機能とページを確認しておきましょう。
掲示板の投稿編集・削除には次の各機能が必要となります。
- ルーティング(urls.pyに記述)
- 投稿編集ページへ遷移するためのボタン(detail.htmlに配置)
- 投稿を削除するためのボタン(detail.htmlに配置)
- 投稿編集用のWebページ(edit.htmlを作成)
- 編集内容をデータベースに保存するedit関数(views.pyに記述)
- 投稿をデータベースから削除するdelete関数(views.pyに記述)
これらを1つずつ作っていきましょう。
ルーティング
ルーティングを記述します。
/bbs/urls.py に次のように記述します。
from django.urls import path from . import views app_name = 'bbs' urlpatterns = [ path('', views.index, name='index'), path('<int:id>', views.detail, name='detail'), path('new', views.new, name='new'), path('create', views.create, name='create'), path('<int:id>/edit', views.edit, name='edit'), # 投稿編集ページのURL path('<int:id>/update', views.update, name='update'), # 編集内容をデータベースに保存する関数のURL path('<int:id>/delete', views.delete, name='delete'), # 投稿を削除する関数のURL ]
ユーザーが /bbs/(id)/edit にアクセスすると views.py の edit関数を、/bbs/(id)/update/ にアクセスすると views.py の update関数を、/bbs/(id)/delete/ にアクセスすると views.py の delete関数をそれぞれ呼び出します。
また、それぞれname属性を付けておいたので、editやdeleteといった名前でこのURLをリンクで呼び出せます。
投稿編集ページへ遷移するためのボタンをdetail.htmlに配置
個別投稿ページに投稿編集ページへの遷移ボタンを配置しておきましょう。
{% extends "./base.html" %} {% block content %} <h1>{{ article.id }}の個別投稿ページ</h1> <p>{{ article.content }}, {{article.user_name }}</p> <div> <button onclick='location.href="{% url "bbs:index" %}"'>一覧</button> <button onclick='location.href="{% url "bbs:edit" article.id %}"'>編集</button> <button onclick='location.href="{% url "bbs:delete" article.id %}"'>削除</button> </div> {% endblock %}
先ほど urls.py でパスを edit や delete という名前で呼び出せるようにしておいたので、8,9行目のリンクでそれぞれ呼び出すことができます。
投稿編集ページを呼び出すedit関数を作成
投稿編集ページを呼び出すための関数を作成します。
フォームは前回の記事で新規投稿用に定義した ArticleForm を流用します。
views.py に次のように追記します。
# 前略 # 投稿編集ページを返すedit関数 def edit(request, id): article = get_object_or_404(Article, pk=id) # 指定した投稿をarticle変数に代入 articleForm = ArticleForm(instance=article) # ArticleFormクラスからarticleFormオブジェクトを生成 context = { 'article': article, 'articleForm': articleForm, } return render(request, 'bbs/edit.html', context) # edit.htmlというテンプレートを返す
特定の投稿の編集ページなので
- 投稿idを受け取ってarticle変数に代入
- それを元にarticleFormオブジェクトを用意してcontextに追加
- テンプレート(edit.html)を呼び出す
これらの処理を記述しています。
投稿編集ページのテンプレート(edit.html)の作成
views.py で呼び出すように記述した edit.html というテンプレートファイルを作成します。
/templates/bbs/ に edit.html という名前でファイルを作成し、次のように記述します。
{% extends "./base.html" %} {% block content %} <h1>Djangoで作る新規投稿フォーム</h1> <form action='{% url "bbs:update" articel.id %}' method="post"> {% csrf_token %}<!-- セキュリティのための記述 --> {{ articleForm }}<!-- views.pyから受け取ったarticleFormを表示 --> <button type='submit'>保存</button> <a href='{% url "bbs:detail" article.id %}'>個別投稿ページへ戻る</a> </form> {% endblock %}
new.html と同様、フォームはforms.py で定義した ArticleForm クラスを元に、views.py の edit関数の中でオブジェクトを作成してテンプレートに渡しているので、テンプレート側では articleForm という変数名を指定するだけで、必要な項目(今回はcontentとUser name)が用意されたフォームを作成してくれます。
また、6行目では「個別投稿ページへ戻る」ボタンをクリックすると update という名前のルートをPOSTメソッドで呼び出すよう記述しています。
※csrf_tokenはDjangoが用意してくれているセキュリティ機能です。フォームがデータを送信する時にトークン情報を一緒に送信し、リクエストを受け取ったViewが、トークンが正しいものがどうか検証し、正常なリクエストだと認められれば処理を実行してくれます。
編集内容をデータベースに保存するupdate関数を作成
次に、投稿編集Webページで「保存」ボタンを押した時に呼び出される update関数を作成しましょう。
views.py に次のように追記します。
# 前略 # 編集データを保存して個別投稿ページを返すupdate関数 def update(request, id): # リクエストのメソッドがPOSTなら if request.method == 'POST': article = get_object_or_404(Article, pk=id) articleForm = ArticleForm(request.POST, instance=article) # ArticleFormクラスからarticleFormオブジェクトを生成 # 受け取ったデータが正常なら if articleForm.is_valid(): articleForm.save() # データを保存 context = { 'article': article, } return render(request, 'bbs/detail.html', context) # detail.htmlを返す
この関数は投稿編集フォームからデータを受け取った時、POSTメソッドかどうか、受け取ったデータが正常かどうかをチェックし、問題なければデータを保存します。
データの保存後はまた個別投稿ページを呼び出すようにしています。
投稿内容をデータベースから削除するdelete関数を作成
次に、投稿編集Webページで「削除」ボタンを押した時に呼び出される delete関数を作成しましょう。
views.py に次のように追記します。
# 前略 # 投稿データを削除するdelete関数 def delete(request, id): article = get_object_or_404(Article, pk=id) # 指定した投稿をarticle変数に代入 article.delete() articles = Article.objects.all() context = { 'articles': articles, } return render(request, 'bbs/index.html', context) # index.htmlを返す
動作確認
それでは動作確認です。
Djangoコマンドを使ってサーバーを起動し、ブラウザで確認してみましょう。
http://127.0.0.1:8000/bbs にアクセスします。
個別投稿ページへアクセスしましょう。
最後の投稿である「テスト」をクリックします。
今回追加した「編集」「削除」ボタンが並んでいます。
「編集」から試してみましょう。
投稿編集ページが表示できました。
実際にデータを編集して「保存」ボタンをクリックしてみましょう。
編集内容が保存されて個別投稿ページが再び表示されました。
一覧ページでも確認してみましょう。
ちゃんと反映されていますね。
もう一度「ファイエル!」の投稿をクリックして個別投稿ページへアクセスしましょう。
次は「削除」ボタンを試してみましょう。
投稿が削除されて、投稿一覧ページへと遷移しました。
投稿の編集・削除機能の完成です!