コメントの新規登録機能も generic モジュールを使わずに作成してみましょう.
まず,views.py にある CreateCommentView( )
クラスを削除するかコメントアウトします.これに伴い,from django.views.generic import CreateView
も不要になります.次に,comments_create(request)
関数を定義します.このとき,投稿フォームを最初に開くときには GET メソッドでこの関数が呼び出され,投稿ボタンを押したときには POST メソッドで呼び出されることに注意してください.
comments/views.py
from django.urls import reverse_lazy
from django.urls import reverse
from django.shortcuts import render
from django.shortcuts import get_object_or_404
# from django.http import HttpResponse
# from django.views.generic import ListView
# from django.views.generic import DetailView
# from django.views.generic import CreateView
from django.views.generic import UpdateView
from django.views.generic import DeleteView
from django.shortcuts import redirect
from django.contrib import messages
from .forms import CommentForm
from .models import Comment
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
# Create your views here.
...(中略)...
# class CreateCommentView(CreateView):
# model = Comment
# form_class = CommentForm
# success_url = reverse_lazy('comments:index')
# def get_context_data(self, **kwargs):
# context = super().get_context_data(**kwargs)
# context['page_title'] = 'コメントの投稿'
# context['form_name'] = 'コメントの投稿'
# context['button_label'] = 'コメントを投稿する'
# return context
# def form_valid(self, form):
# self.object = comment = form.save()
# messages.success(self.request, 'コメントを投稿しました')
# return redirect(self.get_success_url())
def comments_create(request):
if request.method == 'POST':
form = CommentForm(request.POST)
if form.is_valid():
comment = Comment()
comment.title = form.cleaned_data.get("title")
comment.body = form.cleaned_data.get("body")
comment.save()
messages.success(request, '投稿しました')
return redirect(reverse('comments:index'))
else:
# エラーメッセージをつけて返す
context = {}
context['page_title'] = 'コメントの投稿'
context['form_name'] = 'コメントの投稿'
context['button_label'] = 'コメントを投稿する'
context['form'] = form
return render(request, 'comments/form.html', context)
else:
context = {}
context['form'] = CommentForm(
initial={
# 'title' : 'title',
}
)
context['page_title'] = 'コメントの投稿'
context['form_name'] = 'コメントの投稿'
context['button_label'] = 'コメントを投稿する'
return render(request, 'comments/form.html', context)
上の65行目では form.html
を呼び出しています.これは comment_form.html
をコピーして使います.コメントの編集機能でまだ comment_form.html
を利用しているのでファイル名を変更すると編集機能が動作しなくなります(編集機能の書き換え時に削除すると良いでしょう).また,form.html
の 4, 9, 13 行目で参照する page_title
, form_name
, button_label
を views.py の 62〜64 行目で設定しています.
comments/templates/comments/form.html
{% extends 'base.html' %}
{% block title %}
{{ page_title }}
{% endblock %}
{% block content %}
<div class="container">
<h1 class="my-5">{{ form_name }}</h1>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<button type="submit" class="btn btn-primary">{{ button_label }}</button>
</form>
</div>
{% endblock content %}
また,上の views.py 38 行目の form.is_valid( )
によって,フォームの入力データが検証されます.これまでの段階では「未入力」「ホワイトスペースの削除」「入力の最大文字数」の検証だけができており,スペースだけを入力した場合にプログラムが停止してしまう問題が残っていました.この問題を解決するために forms.py を次のように修正します.なお,動作の確認を容易にするため,タイトルと本文の最大文字数をそれぞれ10文字と20文字にしています.
comments/forms.py
from django import forms
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('title', 'body')
widgets = {
'title': forms.TextInput(attrs={
'class': 'form-control'
}),
'body': forms.TextInput(attrs={
'class': 'form-control'
}),
}
labels = {
'title': 'タイトル',
'body': '本文',
}
def clean(self):
data = super().clean()
title = data.get('title')
body = data.get('body')
if title is None:
msg = "タイトルが入力されていません"
self.add_error('title', msg)
elif len(title) > 10:
msg = "タイトルの最大文字数は10文字です"
self.add_error('title', msg)
if body is None:
msg = "本文が入力されていません"
self.add_error('body', msg)
elif len(body) > 20:
msg = "本文の最大文字数は20文字です"
self.add_error('body', msg)
最後に urls.py のルートを修正します.
comments/urls.py
from django.urls import path
from . import views
app_name = 'comments'
urlpatterns = [
path('', views.comments_index, name='index'),
path('<int:comment_id>/', views.comments_show, name='show'),
path('create/', views.comments_create, name='create'),
path('<int:pk>/update/', views.UpdateCommentView.as_view(), name='update'),
path('<int:pk>/delete/', views.DeleteCommentView.as_view(), name='delete'),
]
Webサーバを起動してブラウザで動作を確認します.タイトルには11文字を,本文には空白文字だけを入力して検証されることを確認します.また問題のないタイトルと本文を入力して正しく登録されることも確認します.
(py39) C:\Users\lecture\Documents\django\django_comment>python manage.py runserver ⏎
Watching for file changes with StatReloader
Performing system checks...