Создание форм в Django - CreateView, UpdateView и DeleteView

Формы для блога на Django — CRUD: CreateView, UpdateView и DeleteView

CreateView, UpdateView и DeleteView

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

Содержание статьи

CreateView форма для создания записи на блоге

Формы являются очень важными и в то же время весьма сложными в плане реализации элементами. Во время приема вводных данных от пользователя под удар попадает система безопасности (XSS Attacks), при этом нужно создать продвинутый обработчик ошибок, а также возникает необходимость грамотно настроенного интерфейса UI, который предупреждает пользователей о проблемах с формами. Плюс ко всему здесь требуется добиться успешных перенаправлений на нужную страницу.

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

Для начала обновим базовый шаблон для отображения прямой ссылки на страницу создания новой записи блога. Код будет выглядеть, как <a href="{% url 'post_new' %}"></a>, где post_new является названием нашего URL.

> Есть вопросы по Python?
На нашем форуме вы можете задать любой вопрос и получить ответ от всего нашего сообщества!
Открыть форум

Обновленный файл templates/base.html должен выглядеть следующим образом:

Теперь добавим новый URL-маршрут для страницы создания новой статьи post_new. В верхней части импортируем пока еще не созданное представление под названием BlogCreateView. После этого создаем URL маршрут, с названием post_new, который будет начинаться с post/new/.

Не так уж сложно, верно? Такие же url, представления и шаблоны мы видели ранее.

Теперь перейдем к созданию представления, для чего в верхней части импортируем общий класс представлений под названием CreateView, наследуем его в классе BlogCreateView.

Внутри BlogCreateView указываем на модель Post из прошлого урока и название нашего HTML шаблона post_new.html. Для fields напрямую выбираем поля из таблицы, которые нужно задействовать — в данном случае это title, author и body.

На последнем этапе создаем HTML шаблон, который назовем post_new.html.

Затем добавляем следующий HTML код:

Разберем выполненные выше действия:

  • На верхней строке указан базовый шаблон структуру которого мы будем дополнять;
  • Используются HTML тег <form> с методом POST, так как мы высылаем данные. Если мы получаем данные из поля поиска, тогда мы бы использовали GET;
  • Добавляется специальный токен {% csrf_token %}, через который Django обеспечивает защиту от аттак межсайтового скриптинга. Нужно использовать его для всех форм в Django;
  • Для отображения формы используется {{ form.as_p }}, что помещает форму внутри тега <p>;
  • Под конец создается кнопка «Save» для сохранения изменений из формы.

Для просмотра нашей работы запустите веб-сервер через команду python manage.py runserver и перейдите на страницу http://127.0.0.1:8000/.

формы django

Нажмите на ссылку «+ New Blog Post», которая перенаправит вас на http://127.0.0.1:8000/post/new/.

формы django

Страница добавления новой записи в блоге

Попробуйте создать новую запись на блоге, после чего подтвердите действие нажав на кнопку «Save».

формы django

Ошибка ImproperlyConfigured в Django

Упс! Что же произошло?

ImproperlyConfigured

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

Можно согласиться на предложение Django и добавить к нашей модели новый метод get_absolute_url. Это хорошая практика, которой будет не лишним следовать. Здесь устанавливается прямой URL для объекта, так что даже при возможном изменении структуры URL в будущем, ссылка на некий объект останется прежней. Короче говоря, вам нужно создать методы get_absolute_url() и __str__() для каждой модели.

Откройте файл models.py. Добавьте на второй строке импорт для reverse и новый метод get_absolute_url.

Reverse является довольно полезной вспомогательной функцией Django, что позволяет отсылаться к определенному объекту через название URL маршрута, в данном случае это post_detail. URL маршрут будет следующим:

Это означает, что для работы маршрута также нужно передать аргумент pk или первичный ключ (ID) объекта. Путаницу вызывает тот факт, что в Django pk и id взаимозаменяемы, хотя в документации по Django рекомендуется использовать self.id с get_absolute_url. Итак, мы сообщаем Django, что конечным местоположением записи будет представление post_detail, которое находится по URL маршруту posts/<int:pk>/, следовательно, URL-адрес для первой созданной нами записи будет  posts/1.

Попробуем заново создать запись на блоге, переходим на страницу http://127.0.0.1:8000/post/new/.

формы django

После нажатия кнопки «Save» вы будете перенаправлены на индивидуальную страницу созданной записи.

форма djangoИндивидуальная страница записи

Вернувшись на домашнюю страницу http://127.0.0.1:8000/, вы заметите, что наша предыдущая запись также в списке. Она была успешно создана в базу данных, однако Django не знал, куда после этого перенаправить пользователя.

форма django

Домашняя страница блога с четырьмя записями

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

Форма для обновления данных UpdateView в Django

Процесс создания формы для редактирования, при помощи которой пользователи смогут редактировать записи, может показаться знакомым. Мы вновь используем встроенные в Django общие классовые представления UpdateView и создадим HTML шаблон, url маршрут и представление (views).

Для начала добавим новую ссылку в post_detail.html, таким образом ссылка на редактирование записи можно будет найти на индивидуальной странице самой записи.

Мы добавили ссылку, используя HTML тег <a href>...</a>, и тег языка шаблонов {% url ... %}. Внутри мы уточнили структуру url, которое будет называться post_edit, а также передали запрашиваемый параметр, которым является первичный ключ записи post.pk.

Далее создается HTML шаблон для отдельной страницы редактирования данных, которая будет называться post_edit.html.

Добавляем следующий код:

Мы вновь используем теги <form></form>, для обеспечения безопасности добавим csrf_token от Django, form.as_p для отображения полей формы и, конечно же, создаем кнопку «Update» для подтверждения изменений.

Теперь перейдем к представлению. На второй строке сверху импортируется общий класс представления UpdateView, после чего наследуем его в BlogUpdateView.

Обратите внимание, что в BlogUpdateView мы перечисляем по отдельности нужные поля ['title', 'body'] вместо использования '__all__'. Это делается из-за того, что предполагается, будто автор записи не изменится, а редактироваться будет только заголовок и содержимое поста.

На финальном этапе обновляется файл urls.py. В верхней части добавляется класс BlogUpdateView, а затем новый URL маршрут.

В верхней части мы добавляем представление BlogUpdateView к списку импортированных представлений, затем создаем новый url маршрут  /post/pk/edit и называем его post_edit.

Теперь при переходе на страницу записи, мы увидим ссылку на страницу редактирования данной статьи «+ Edit Blog Post«.

форма django

Страница блога с кнопкой редактирования

При нажатии на «+ Edit Blog Post» вы будете перенаправлены на страницу http://127.0.0.1:8000/post/1/edit/ в том случае, если это была ваша первая запись в блоге, т.к. ID = 1.

форма djangoСтраница редактирования записи

Обратите внимание, что форма заполнена уже существующей в базе данных информацией. Изменим ее…

форма djangoСтраница редактирования записи блога

При нажатии кнопки «Update» происходит перенаправление на страницу самой записи, которая уже изменена. Это происходит благодаря настройке метода get_absolute_url. Перейдя на домашнюю страницу сайту, можно увидеть обновленные записи.
форма django

Домашняя страница с отредактированной записью

Создаем страницу удаления записи DeleteView

Процесс создания формы для удаления записи очень похож на то, что мы делали с формой обновления записи. Сейчас приступим к созданию представления, url маршрутов и HTML-шаблона. На данном этапе мы будет использовать общее классовое представление DeleteView.

Начнем с добавления ссылки для удаления записи, поместим ее на индивидуальной странице поста post_detail.html.

Далее создаем новый HTML файл для шаблона страницы подтверждения удаления записи. Закрываем локальный веб-сервер через комбинацию CTRL+C и затем набираем следующую команду:

Заполняем файл следующим кодом:

Обратите внимание, что для отображения заголовка записей блога здесь используется post.title. Можно использовать и object.title, который также поставляется в DetailView.

Далее обновляем файл views.py, импортируя DeleteView и reverse_lazy в верхней части, после чего создаем новый класс (представление), которое становится наследником от DeleteView.

Вместо reverse здесь используется reverse_lazy, таким образом пользователь не будет перенаправлен до тех пор, пока представление не завершит удаление записи из базы данных.

И теперь можно создать новый URL маршрут при помощи импорта представления BlogDeleteView и добавлении следующих изменений:

Если вновь запустить веб-сервер через python manage.py runserver и обновить страницу записи, можно увидеть новую ссылку «Delete Blog Post«.

delete form

При нажатии на ссылку, пользователь перенаправляется на страницу подтверждения удаления записи, на которой находится только название записи и кнопка подтверждения действий «Confirm«.

delete form

Страница для удаления записи

При нажатии кнопки «Confirm» пользователь будет перенаправлен на домашнюю страницу блога. В списке на главной странице больше не будет удаленная нами запись.

delete form

Итак, все работает!

Тестируем добавление, обновление и удаление записей через TestCase

Пришло время для тестов — убедимся, что все работает должным образом. К нашей модели мы добавили метод get_absolute_url, а также новые представления для создания, обновления и удаления записей. Это значит, что нам понадобится четыре новых теста:

  • def test_get_absolute_url;
  • def test_post_create_view;
  • def test_post_update_view;
  • def test_post_delete_view.

Обновляем существующий файл tests.py следующим образом:

Предполагается, что URL для нашего теста — post/1/. Здесь только одна запись, и 1 — ее первичный ключ, который Django добавляет автоматически. Чтобы протестировать представление для создания (create), создается новый запись. Затем нужно убедиться, что ответ действительно получен (Код HTTP состояния 200) и содержит новый заголовок и тело статьи с текстом. Чтобы протестировать представление для обновления записи (update), требуется получить доступ к первой записи, у которой pk равен 1, который передается как единственный аргумент.

Затем подтверждается факт перенаправления с HTTP кодом 302. Под конец тестируем представление для удаления записи (delete). После удаления записи должен появиться HTTP код состояния 302, и произведено перенаправление на главную страницу, так как удаленного элемента больше не существует.

Упомянутые выше тесты охватывают все возможности нашего блога на Django. Однако всегда есть возможность добавить новые возможности на сайте. Запустите данные тесты сейчас — они все должны пройти.

Заключение

При помощи относительно небольшого количества кода нам удалось создать блог на Django, который позволяет создавать, читать, обновлять и удалять записи. Данная функциональность известна под аббревиатурой CRUD: Create-Read-Update-Delete. Существует несколько способов достижения того же результата. Можно использовать представления на основе функций или же написать свои собственные представления на основе классов. По ходу разбора примеров было продемонстрировано, что для осуществления запрашиваемых операции в Django требуется совсем немного кода.

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

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