Все еще нужна форма, чтобы пользователи могли оставлять комментарии к записям. В Django есть два базовых класса для построения форм: Form
и ModelForm
. Первый уже использовался для того, чтобы пользователи могли делиться постами через электронную почту. Сейчас нужно использовать ModelForm
, потому что форму необходимо создавать динамически на основе Comment
. Отредактируйте файл forms.py
приложения blog
и добавьте следующие строки:
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('name', 'email', 'body')
Для создания формы на основе модели нужно просто указать, какую модель взять за основу в классе формы Meta
. Django исследует модель и строит форму динамически. Каждое поле модели имеет соответствующий тип поля формы по умолчанию. Способ, которым были определены поля модели, учитывается при проверке формы. По умолчанию Django создает поле формы для каждого поля модели. Но можно явно указать фреймворку, какие поля нужны в форме с помощью списка fields
или определения того, какие поля нужно исключить с помощью списка полей exclude
. Для формы CommentForm
будут использоваться name
, email
и body
, потому что это единственное, что нужно заполнять.
Обработка ModelForms в представлениях
Для простоты представление поста будет использоваться для создания экземпляра формы и ее обработки. Отредактируйте файл views.py
, добавьте импорты для модели Comment
и формы CommentForm
и отредактируйте представление post_detail
, чтобы оно выглядело вот так:
from .models import Post, Comment
from .forms import EmailPostForm, CommentForm
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status='published',
publish__year=year,
publish__month=month,
publish__day=day)
# Список активных комментариев к этой записи
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
# Комментарий был опубликован
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# Создайте объект Comment, но пока не сохраняйте в базу данных
new_comment = comment_form.save(commit=False)
# Назначить текущий пост комментарию
new_comment.post = post
# Сохранить комментарий в базе данных
new_comment.save()
else:
comment_form = CommentForm()
return render(request,
'blog/post/detail.html',
{'post': post,
'comments': comments,
'new_comment': new_comment,
'comment_form': comment_form})
Разберем, что есть в представлении. Представление post_detail
используется для отображения поста и комментариев. С помощью QuerySet можно получить все активные комментарии:
comments = post.comments.filter(active=True)
Начинается этот QuerySet с объекта post
. Менеджер для связанных объектов, определенный в comments
, используется при помощи атрибута related_name
отношения в модели Comment
.
То же представление используется для того, чтобы пользователи могли оставлять комментарии. Переменная new_comment
инициализируется при передаче ей значения None
. Она создается при создании комментария. Экземпляр формы создается с помощью comment_form = CommentForm()
, если представление вызывается посредством запроса GET
. Если он делается через POST
, форма экземпляра создается с помощью отправленных данных и проверяется через метод is_valid()
. Если форма неверна, рендерится шаблон с ошибками проверки. Если правильная — выполняются следующие действия:
- Создается новый объект
Comment
посредством вызова метода формыsave()
и присваивания его переменнойnew_comment
следующим образом:new_comment = comment_form.save(commit=False)
Метод
save()
создает экземпляр модели, к которой привязана форма и сохраняет ее в базу данных. Если ее вызвать с помощьюcommit=False
, то экземпляр будет создан, но сохранение в базу данных не состоится. Это удобно, когда нужно изменить объект перед сохранением. А это следующий этап.Метод
save()
доступен дляModelForm
, но не для экземпляровForm
, потому что они не привязаны ни к одной модели. - Текущий пост присваивается созданному комментарию:
new_comment.post = post
Таким образом отмечается, что этот комментарий принадлежит этому посту.
- Наконец, новый комментарий сохраняется в базу данных через метод
save()
:new_comment.save()
Представление готово отображать и обрабатывать новые комментарии.