Django 5 для начинающих

Прогресс по курсу:  9/1004

6.5 Создание системы комментариев
4 из 8 шагов пройдено
0 из 16 баллов  получено

Создание форм из моделей

Далее необходимо скомпоновать форму, позволяющую пользователям комментировать посты блога. Напомним, что в 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-адресами. Давайте создадим необходимые шаблоны в следующем шаге.


  • Комментариев
Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий

Илья, получается, добавления декоратора @require_POST, позволяет в самой функции не проверять if request.method == 'POST': 

@Агаси_Мироян, ага, все верно, чтобы представление принимало только метод POST.

@Илья_Перминов, Спасибо, Илья. Вы всегда подробно и оперативно отвечаете на мои вопросы. Вы хороший учитель. 

С помощью курса конечно получается строить блог, но пока не могу себе представить чтобы я такое сделал сам. Сильно много объектов, у каждого полно методов, запомнить все просто нереально. Надеюсь с опытом пройдет.

@Георгий_Тимофеев, все придет с опытом. Особенно большое понимание придет когда начнете писать что-то свое, беря различные части кода из этого курса. Тут уже придется адаптировать код под свои задачи, разбираясь в его работе. А в итоге пазлы в голове сложатся, и вам многое станет понятно.

@Георгий_Тимофеев, всё придет со временем, главное не бросать программирование на долго.

@Георгий_Тимофеев, Не надо стараться запомнить все, это действительно нереально. Попробуйте запоминать только базовые сущности и приемы, и где посмотреть, если забылось. 

чтобы понять пришлось 2 раза прочитать.
Я бы ввел какие-нибудь пометки, чтобы указывать на те места, где функция или метод зашит в кишки джанго. Чтобы потом быстро находить это в конспекте 

Чем отличаются записи 'form = CommentForm(data=request.POST)' и 'form = CommentForm(request.POST)'? Зачем указывать параметр data?

@Александр_Ёлшин, Ничем не отличаются, можно использовать оба варианта, именованный параметр data это первый позиционный параметр.

"Мы используем предоставляемый веб-фреймворком Django декоратор require_POST, чтобы разрешить запросы методом POST только для этого представления."

Мы используем предоставляемый веб-фреймворком Django декоратор require_POST, чтобы разрешить для этого представления только запросы методом POST(запросы только методом POST) .

 

Мне кажется, что в вашей версии не совсем верно отражается суть.

@Aleksandr_Gurov, Спасибо, поправил.