前回はログイン機能を実装しましたが、今回は新規投稿ができるように改良します。
作成した掲示板はこんな感じになります。 ⇒ 動作確認はこちらから
新規投稿できるようにする
まず新規投稿のページを表示させるためのテンプレートを作成します。これは既存の投稿を編集し更新する処理でも使います。テンプレートの場所は{プロジェクト名}/bbs\templates\bbsディレクトリ内です。
article_form.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{% extends 'layout.html' %} {% block content %} <h1 class="mt-3 mb-4">{{ object|yesno:'投稿内容の更新,新規投稿の作成'}}</h1> <form action='' method='post'> {% csrf_token %} <p>タイトル:{{ form.title }}</p> <p>本文:<br> {{ form.content }}</p> <button type='submit' class='submit btn btn-outline-primary'>{{ object|yesno:'更新,作成'}}</button> </form> <div class="mt-3"> <a href='JavaScript:history.back()' class='btn btn-outline-primary'>< 戻る</a> </div> {% endblock %} |
それからarticle_list.htmlとarticle_detail.htmlの最初の行を{% extends ‘layout.html’ %}に変更してしまいましょう。そうするとトップページと個別ページにもログインしているかどうかを示すナビゲーションバーが表示されるようになります。
次にbbsディレクトリ内のviews.pyを以下のように変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
from django.shortcuts import render from django.http import HttpResponse from .models import Article from django.views import generic from django.urls import reverse_lazy from django.contrib.auth.mixins import LoginRequiredMixin from django.core.exceptions import PermissionDenied class CreateView(LoginRequiredMixin, generic.edit.CreateView): model = Article fields = ['content', 'title', ] def form_valid(self, form): form.instance.author = self.request.user return super(CreateView, self).form_valid(form) |
次にbbsディレクトリ内のurls.pyを以下のように変更します。
1 2 3 4 5 6 7 |
urlpatterns = [ # path('create/', views.create, name='create'), path('create/', views.CreateView.as_view(), name='create'), # 他は変更しない ] |
またトップページの下部に新規投稿用のボタンを設置します。
article_list.htmlの{% endblock %}のすぐ上の行に以下を追加します。
article_list.html
1 2 3 4 5 |
{% if user.is_authenticated %} <p> <a href='{% url "bbs:create" %}' class='btn btn-outline-primary'>新規投稿</a> </p> {% endif %} |
これでログインしているときは新規投稿のボタンが表示されます。
投稿内容を編集・更新できるようにする
次に投稿内容を変更するための処理を実装します。
次にbbsディレクトリ内のviews.pyを以下のように変更します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 削除 # def update(request, id): # return HttpResponse('update ' + str(id)) class UpdateView(LoginRequiredMixin, generic.edit.UpdateView): model = Article fields = ['content', 'title', ] def dispatch(self, request, *args, **kwargs): obj = self.get_object() if obj.author != self.request.user: raise PermissionDenied('You do not have permission to edit.') return super(UpdateView, self).dispatch(request, *args, **kwargs) |
次にbbsディレクトリ内のurls.pyを以下のように変更します。<int:id>が<int:pk>に変更されているので注意してください(自分がハマった)。
1 2 3 4 5 6 |
urlpatterns = [ # path('<int:id>/update/', views.update, name='update'), path('<int:pk>/update/', views.UpdateView.as_view(), name='update'), # 他は変更しない ] |
これで http://localhost:8000/bbs/{pk}/update/ にアクセスすると自分の投稿を編集できるようになります。またログインしていない場合や違うアカウントで投稿されたページを編集しようとした場合は403 Forbiddenと表示され、アクセスできません。
投稿を削除できるようにする
次に自分の投稿を削除できるようにします。
削除するときは確認のページが表示されますが、それを表示させるためのテンプレートを作成します。
作成する場所は{プロジェクト名}\bbs\templates\bbsディレクトリ内です。ファイル名はarticle_confirm_delete.htmlです。これもこの名前にしなければなりません。
article_confirm_delete.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
{% extends 'layout.html' %} {% block content %} <h1>投稿の削除</h1> <p>以下を削除しますか?</p> <p>{{ article.content }}</p> <p>{{ article.user_name }}</p> <p>{{ article.author }}</p> <p>{{ article.created_at|date:"Y-m-j H:i:s" }}</p> <p>{{ article.updated_at|date:"Y-m-j H:i:s" }}</p> <form action='' method='post'>{% csrf_token %} <a href='JavaScript:history.back()' class='btn btn-outline-primary'>削除しないで戻る</a> <button type='submit' class='submit delete btn btn-danger'>削除する</button> </form> {% endblock %} |
次にbbsディレクトリ内のviews.pyを以下のように変更します。
1 2 3 4 5 6 7 |
# 削除 # def delete(request, id): # return HttpResponse('delete ' + str(id)) class DeleteView(LoginRequiredMixin, generic.edit.DeleteView): model = Article success_url = reverse_lazy('bbs:index') |
これで投稿が削除され、http://localhost:8000/bbs/ にリダイレクトされます。
次にbbsディレクトリ内のurls.pyを以下のように変更します。<int:id>が<int:pk>に変更されているので注意してください。
1 2 3 4 5 6 |
urlpatterns = [ # 削除 path('<int:id>/delete/', views.delete, name='delete'), path('<int:pk>/delete/', views.DeleteView.as_view(), name='delete'), # 他は変更しない ] |
投稿内容を編集したり削除できるように投稿内容が表示されているページからリンクをはります。このときに編集と削除ができるアカウントでログインしていない場合はリンク自体が表示されないようにします。
{% if request.user.id == object.author_id %} と {% endif %} で挟まれた部分は投稿したアカウントでログインしているときしか表示されません。
article_detail.html
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
{% extends 'layout.html' %} {% block content %} <div> <p>タイトル:{{ article.title }}</p> <p>投稿内容:<br>{{ article.content }}</p> <p>{{ article.author }}</p> <p>{{ article.created_at|date:"Y-m-j H:i:s" }}<br> {{ article.updated_at|date:"Y-m-j H:i:s" }}</p> </div> <div class='mt-4'> {% if request.user.id == object.author_id %} <a href='{% url "bbs:update" article.pk %}' class='btn btn-outline-primary mr-2'>編集</a> {% endif %} <a href='{% url "bbs:index" %}' class='btn btn-outline-primary'>一覧に戻る</a> {% if request.user.id == object.author_id %} <a href='{% url "bbs:delete" article.pk %}' class='btn btn-danger ml-5'>削除</a> {% endif %} </div> {% endblock %} |
これで投稿を削除することができるようになりました。