Классы CreateView и UpdateView

Курс по Django: https://stepik.org/a/183363

Архив проекта: 55_sitewomen.zip

Если мы посмотрим на список классов представлений:

https://docs.djangoproject.com/en/4.2/ref/class-based-views/

то увидим, что после FormView следуют классы CreateView, UpdateView и DeleteView. По их названиям легко догадаться, что они еще более специализированы, чем класс FormView. В частности, для добавления (то есть, создания) новой статьи мы могли бы вместо FormView использовать класс CreateView. Давайте это сделаем.

Уберем из класса AddPage метод form_valid и унаследуем класс от CreateView, получим:

class AddPage(CreateView):
    form_class = AddPostForm
    template_name = 'women/addpage.html'
    success_url = reverse_lazy('home')
    extra_context = {
        'menu': menu,
        'title': 'Добавление статьи',
    }

После запуска тестового веб-сервера, видим тот же самый результат. Мало того, мы здесь можем удалить атрибут success_url, тогда маршрут перенаправления будет определяться на основе метода get_absolute_url() модели Women. Класс CreateView обращается к этому методу для получения URL-адреса добавленной статьи и перенаправляет нас к ней. Видите, как полезно следовать конвенции Django и определять стандартные методы.

Таким образом, класс CreateView берет дополнительно на себя весь функционал по сохранению данных формы в БД. Причем, модель была взята из класса AddPostForm, так как это форма, связанная с моделью. При необходимости, мы можем использовать класс CreateView с любой другой моделью без указания формы. Для этого следует в нем определить атрибут model следующим образом:

class AddPage(CreateView):
    model = Women
    # form_class = AddPostForm
    template_name = 'women/addpage.html'
    success_url = reverse_lazy('home')
    extra_context = {
        'menu': menu,
        'title': 'Добавление статьи',
    }

Атрибут form_class, конечно же, нужно убрать. Если в таком виде попытаться отобразить страницу добавления поста, то увидим ошибку, что не определена коллекция fields для указания отображаемых на форме полей. Пропишем этот атрибут в виде:

fields = '__all__'

В результате, будут отображены все поля формы с названиями, указанными в параметре verbose_name модели Women.

Если же требуется строго определенный набор полей, то вместо строки '__all__' следует прописать список с названиями полей из модели Women. Например, так:

fields = ['title', 'slug', 'content', 'is_published', 'cat']

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

Конечно, в этом списке должны быть перечислены все обязательные для заполнения поля. Например, если мы уберем поле ‘cat’:

fields = ['title', 'slug', 'content', 'is_published']

то при добавлении возникнет ошибка, что это поле не указано. Поэтому все, что нужно пользователю заполнить, следует отображать в форме. Либо делать автозаполнение на программном уровне.

Вообще, какой вариант использовать для класса CreateView, конечно же, решает сам программист, исходя из логики и удобства написания программного кода. Я здесь лишь показываю возможности отдельных классов представлений, принципы их работы. А конкретная реализация, конечно, должна вытекать из понимания работы этих классов и общей архитектуры создаваемого проекта.

Класс UpdateView

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

Объявим класс UpdatePage (после класса AddPage) и унаследуем его от базового класса UpdateView:

class UpdatePage(UpdateView):
    model = Women
    fields = ['title', 'content', 'photo', 'is_published', 'cat']
    template_name = 'women/addpage.html'
    success_url = reverse_lazy('home')
    extra_context = {
        'menu': menu,
        'title': 'Редактирование статьи',
    }

Остальное содержимое я оставил практически таким же, как и в классе AddPage, только коллекцию fields немного изменил (убрал поле slug и добавил поле photo).

Осталось связать этот класс с маршрутом. Перейдем в файл women/urls.py и в коллекции urlpatterns добавим строчку:

urlpatterns = [
    ...
    path('edit/<int:pk>/', views.UpdatePage.as_view(), name='edit_page'),
    ...
]

Обратите внимание на параметр pk в этом маршруте. Это специальное имя (сокращение от слов primary key – главный ключ), по которому автоматически будет отбираться запись для редактирования в классе UpdatePage. То есть, запись будет выбираться по ее идентификатору (полю id).

Давайте посмотрим, как это будет работать. Перейдем, например, по адресу:

http://127.0.0.1:8000/edit/1/

и видим отображение формы с заполненными полями записи с идентификатором 1. Мы можем поменять здесь какие-либо данные и после нажатия на кнопку «Добавить», запись будет изменена в БД.

Видите, как просто в Django можно реализовать такой функционал? В таких вещах и состоит главное преимущество фреймворков, по сравнению с созданием чего-либо с нуля. Здесь все типовые моменты уже внедрены и отработаны. Нам остается только изучить возможности Django и использовать их в своих проектах.

Если мы хотим отбирать записи не по id, а по слагу (slug), то в маршруте вместо параметра pk следует прописать slug с соответствующим конвертером:

path('edit/<slug:slug>/', views.UpdatePage.as_view(), name='edit_page'),

Все, теперь статьи автоматически выбираются по полю slug. Соответственно, в модели это поле так и должно называться – slug.

Заключение

Ну а последний подобный класс DeleteView разберите самостоятельно. Используется он аналогично ранее рассмотренным классам CreateView и UpdateView. Подробно о нем написано в документации:

https://docs.djangoproject.com/en/4.2/ref/class-based-views/generic-editing/#deleteview

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

Курс по Django: https://stepik.org/a/183363

Видео по теме