Создание форм из моделей
Далее необходимо скомпоновать форму, позволяющую пользователям комментировать посты блога. Напомним, что в Django есть два базовых класса, которые можно использовать для создания форм: Form и ModelForm.
Мы использовали класс Form, чтобы предоставлять пользователям возможность делиться постами по электронной почте.
Теперь мы будем использовать 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 в явном виде. Это единственные поля, которые будут включены в форму.
Оперирование формами ModelForm в представлениях
Для того чтобы делиться постами по электронной почте, мы использовали одно и то же представление, которое служило как для отображения формы, так и для управления ее передачей на обработку. Мы использовали HTTP-метод, чтобы проводить различие между обоими случаями, GET, чтобы отображать форму на странице, и POST, чтобы передавать ее на обработку.
В этом случае мы добавим форму комментариев на страницу детальной информации о посте и разработаем отдельное представление, которое посвящено передаче формы на обработку. Новое обрабатывающее форму представление позволит пользователю возвращаться к представлению детальной информации о посте, после того как комментарий будет сохранен в базе данных.
Отредактируйте файл views.py приложения blog, добавив следующий ниже исходный код:
from django.shortcuts import render, get_object_or_404, redirect
from .models import Post, Comment
from django.core.paginator import Paginator, EmptyPage, PageNotAnInteger
from django.views.generic import ListView
from .forms import EmailPostForm, CommentForm
from django.core.mail import send_mail
from django.views.decorators.http import require_POST
# ...
@require_POST
def post_comment(request, post_id):
post = get_object_or_404(Post,
id=post_id,
status=Post.Status.PUBLISHED)
comment = None
# Комментарий был отправлен
form = CommentForm(data=request.POST)
if form.is_valid():
# Создать объект класса Comment, не сохраняя его в базе данных
comment = form.save(commit=False)
# Назначить пост комментарию
comment.post = post
# Сохранить комментарий в базе данных
comment.save()
return render(request, 'blog/post/comment.html',
{'post': post,
'form': form,
'comment': comment})
Мы определили представление post_comment, которое принимает объект request и переменную post_id в качестве параметров.
Мы будем использовать это представление, чтобы управлять передачей поста на обработку.
Мы ожидаем, что форма будет передаваться с использованием HTTP-метода POST.
Мы используем предоставляемый веб-фреймворком Django декоратор require_POST, чтобы разрешить для этого представления только запросы методом POST.
Django позволяет ограничивать разрешенные для представлений HTTP-методы. Если пытаться обращаться к представлению посредством любого другого HTTP-метода, то Django будет выдавать ошибку HTTP 405 (Метод не разрешен).
В этом представлении реализованы следующие ниже действия:
1. По id поста извлекается опубликованный пост, используя функцию сокращенного доступа get_object_or_404().
2. Определяется переменная comment с изначальным значением None. Указанная переменная будет использоваться для хранения комментарного объекта при его создании.
3. Создается экземпляр формы, используя переданные на обработку POST-данные, и проводится их валидация методом is_valid(). Если форма не валидна, то шаблон прорисовывается с ошибками валидации.
4. Если форма валидна, то создается новый объект Comment, вызывая метод save() формы, и назначается переменной comment, как показано ниже:
comment = form.save(commit=False)
5. Метод save() создает экземпляр модели, к которой форма привязана, и сохраняет его в базе данных. Если вызывать его, используя commit=False, то экземпляр модели создается, но не сохраняется в базе данных. Такой подход позволяет видоизменять объект перед его окончательным сохранением.
6. Пост назначается созданному комментарию:
comment.post = post
7. Новый комментарий создается в базе данных путем вызова его метода save():
comment.save()
8. Прорисовывается шаблон blog/post/comment.html, передавая объекты post, form и comment в контекст шаблона. Этот шаблон еще не существует, мы создадим его позже.
Давайте создадим шаблон URL-адреса этого представления. Отредактируйте файл urls.py приложения blog, добавив следующий ниже шаблон URL-адреса:
path('<int:post_id>/comment/',
views.post_comment, name='post_comment'),
Мы реализовали представление, чтобы управлять передачей комментариев на обработку и соответствующими им URL-адресами. Давайте создадим необходимые шаблоны в следующем шаге.