【Django】DetailViewのhtmlページ中のモーダルダイアログでUpdateView処理を行いたい

実現したいこと

Djangoで会員登録制の記事公開アプリケーションを作成しています。
記事詳細ページ内に表示されるコメントを編集する機能を同ページ内のモーダルダイアログに実装しようとしています。

前提

記事詳細ページ(article_detail.html)の機能要件は下記の通りになります。
・記事内容の表示
・記事の編集/削除(リクエストユーザーが記事の著者である場合のみ)
・記事に対するコメントの表示
・記事に対するコメントの作成
・コメントの編集/削除(リクエストユーザーがコメントの著者である場合のみ)

これらの機能のうち、記事の編集/削除は遷移先の別ページにて処理を行わせています。一方で、コメントの作成とコメントの編集/削除は記事詳細ページ内で処理を行う設計で、特にコメントの編集/削除はモーダルダイアログで処理を行わせたいと考えています。

モデルとフォーム

モデルはユーザ情報に関するCustomUser、記事に関するArticle、記事へのコメントに関するCommentモデルを用意しています。

models.py

1class CustomUser(AbstractUser): 2 3 username = models.CharField( 4 _("username"), 5 max_length=30, 6 help_text='Required 30 characters or fewer.', 7 unique=True, 8 error_messages={ 9 'unique': _("This Username already exists."), 10 },) 11 12 email = models.EmailField( 13 _('email'), 14 unique=True, 15 error_messages={ 16 'unique': _("A user with that email address already exists."), 17 },) 18 19 class Meta: 20 verbose_name_plural = 'CustomUser' 21 22 23class Article(models.Model): 24 25 post_user = models.ForeignKey(CustomUser, verbose_name='Post User', on_delete=models.CASCADE, related_name='name',) 26 title = models.CharField(verbose_name='title', max_length=50,) 27 content = MDTextField() 28 created_at = models.DateField(verbose_name='created_at', auto_now_add=True,) 29 30 class Meta: 31 verbose_name_plural = 'Article' 32 33 def __str__(self): 34 return self.title 35 36class Comment(models.Model): 37 #記事に対するコメント 38 writer = models.ForeignKey(CustomUser, on_delete=models.CASCADE,) 39 text = MDTextField() 40 target = models.ForeignKey(Article, on_delete=models.CASCADE,) 41 created_at = models.DateField(verbose_name='created_at', auto_now_add=True,) 42 updated_at = models.DateField(verbose_name='updated_at', auto_now=True,) 43 44 def __str__(self): 45 return self.text[:20]

コメントの作成及び編集にはCommentCreateFormを用意しています。

forms.py

1class CommentCreateForm(forms.ModelForm): 2 class Meta: 3 model = Comment 4 fields = ("text",)

ビューとテンプレート

コード表示簡素化のため、ビューとルーティングではコメント削除機能を省略しています。また同様の理由で、テンプレートではモーダルの部分だけ記載いたします。

views.py

1#記事詳細ページ 2class ArticleDetailView(generic.DetailView): 3 model = Article 4 template_name = 'article_detail.html' 5 6 def get_context_data(self, **kwargs): 7 context = super().get_context_data(**kwargs) 8 9 #コメント作成フォームを渡す 10 context['form'] = CommentCreateForm() 11 #コメント修正フォームを渡す 12               context['comment_form'] = CommentCreateForm() 13 #記事に紐づくコメントを渡す 14 context['comment_list'] = Comment.objects.select_related('target').filter(target=self.kwargs['pk']) 15 16 return context 17 18#コメント関連 19class CommentCreateView(generic.CreateView, LoginRequiredMixin): 20 model = Comment 21 form_class = CommentCreateForm 22 template_name = 'article_detail.html' 23 24 def form_valid(self, form): 25 comment = form.save(commit=False) 26 27 post_pk = self.kwargs['pk'] 28 post = get_object_or_404(Article, pk=post_pk) 29 30 comment.writer = self.request.user 31 comment.target = post 32 comment.save() 33 messages.success(self.request, 'You added a comment!') 34 return super().form_valid(form) 35 36 def get_success_url(self): 37 return reverse_lazy('article:article_detail', kwargs={'pk': self.kwargs['pk']}) 38 39class CommentUpdateView(generic.UpdateView, LoginRequiredMixin): 40 model = Comment 41 form_class = CommentCreateForm 42 template_name = 'article_detail.html' 43 44 def get_success_url(self): 45 return reverse_lazy('article:article_detail', kwargs={'pk': self.kwargs['pk']}) 46 47 def form_valid(self, form): 48 messages.success(self.request, 'Your comment has been successfully updated.') 49 return super().form_valid(form) 50 51 def form_invalid(self, form): 52 messages.error(self.request, 'Failed to correct comment.') 53 return super().form_invalid(form)

urls.py

1app_name = 'article' 2 3urlpatterns = [ 4 path('article_detail/<int:pk>', views.ArticleDetailView.as_view(), name='article_detail'), 5 path('<int:pk>/comment', views.CommentCreateView.as_view(), name='comment_create'), 6 path('<int:pk>/comment/update', views.CommentUpdateView.as_view(), name='comment_update'), 7]

article_detail.html

1{% for comment in comment_list %} 2-中略- 3<ul class="navbar-nav"> 4 <li class="nav-item dropdown"> 5 <a class="nav-link" href="#" id="navbarDropdown" role="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"> 6 <img class="rounded-circle u-box-shadow-sm mr-2" width="25" height="25" src="{% static 'img/three_dots_icon.png' %}" alt="Icon"> 7 </a> 8 9 <!-- モーダルトリガー(プルダウンメニューの項目) --> 10 <div class="dropdown-menu" aria-labelledby="navbarDropdown"> 11 <a class="dropdown-item" id="showModal" data-toggle="modal" data-target="#commentModal">Edit</a> 12 <a class="dropdown-item" href="#">Delete</a> 13 </div> 14 15 <!-- モーダルダイアログ --> 16 <div class="modal fade bd-example-modal-lg" id="commentModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true"> 17 <div class="modal-dialog modal-lg" role="document"> 18 <div class="modal-content"> 19 <div class="modal-header"> 20 <h5 class="modal-title" id="exampleModalLabel">Modify a Comment</h5> 21 <button type="button" class="close" data-dismiss="modal" aria-label="Close"> 22 <span aria-hidden="true">&times;</span> 23 </button> 24 </div> 25 <div class="modal-body"> 26 <form class="text-center w-md-75 mx-auto" method="POST" enctype="multipart/form-data" action="{% url 'article:comment_update' object.pk %}"> 27 {% csrf_token %} 28 {{ form.non_field_errors }} 29 {{ form.media }} 30 31 {% for field in comment_form %} 32 <div class="col-xl-12 form-group mb-4"> 33 {{ field|markdown|safe }} 34 {{ field.errors }} 35 </div> 36 {% endfor %} 37 </form> 38 </div> 39 <div class="modal-footer"> 40 <button type="button" class="btn btn-primary" data-dismiss="modal">Cancel</button> 41 <button type="submit" class="btn btn-primary">Save changes</button> 42 </div> 43 </div> 44 </div> 45 </div> 46 </li> 47</ul> 48 49-中略- 50{% endfor %}

発生している問題

モーダルダイアログ内にフォーム自体を表示させることはできるのですが、修正したいコメントの内容がフォームに入力されていない問題が発生します。また、コメント修正のフォーム送信ボタンを押しても、ビューで指定したリダイレクト先へ遷移等行われず、画面が変わらないままになります。

考えたこと

修正フォームのインスタンス作成失敗

viewsでテンプレートへ渡すフォームをコンテキストデータとして用意する部分で、context['comment_form'] = CommentCreateForm()としているため、修正したいコメントの内容がフォームに入力されていない問題が発生しているのだと考えました。本来であれば、対象とするCommentモデルのレコードをキャプチャし、context['comment_form'] = CommentCreateForm(X=???)とすべきなのかと思いましたが、Xと???の部分をどう指定すべきか調べても分かりませんでした。

Commentレコードのキャプチャの失敗

テンプレートのフォームの送信先としてaction="{% url 'article:comment_update' object.pk %}"としている部分に問題があるのだと考えました。そもそもobject.pkArticleモデルのレコードキャプチャであり、Commentモデルのレコードキャプチャにをするには別の記述方法をしなければならないと思いましたが、自力では分かりませんでした。

上記二点以外でも問題点あれば、ご指摘やアドバイス等いただけると幸いです。

コメントを投稿

0 コメント