Что такое HTML-формы. Отправка данных по GET и POST-запросам

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

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

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

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

Это и есть формы. В HTML они задаются тегом <form> и служат для передачи на сервер пользовательской информации, например, логина и пароля для входа на сайт. На этом занятии мы увидим, как реализуются формы во фреймворке Django. Подробную документацию об этом вы можете почитать в разделе «Формы» на странице сайта:

https://docs.djangoproject.com/en/4.2/#forms

Первое, что нужно знать, это то, что формы в Django можно создавать либо в связке с моделью какой-либо таблицы БД. Тогда получаем формы, связанные с моделью. Например, когда мы выполняем авторизацию или регистрацию на сайте, то этот процесс, очевидно, связан с данными таблиц. Соответственно, используются формы, связанные с моделями. Либо можно создавать независимые формы, не привязанные к моделям. Например, когда создается простой поиск или идет отправка письма на электронную почту. Если при этом обращение к БД не требуется, то и форма создается как независимая, самостоятельная.

Сначала мы рассмотрим форму, не связанную с моделью, хотя и сделаем это на примере добавления статей в БД. Но, затем, модифицируем ее и превратим в форму, связанной с моделью.

Начнем с того, что в главном меню у нас уже есть пункт для добавления статей и функция представления addpage (в файле women/views.py). Немного изменим эту функцию так, чтобы она отображала шаблон addpage.html:

def addpage(request):
    return render(request, 'women/addpage.html', {'menu': menu, 'title': 'Добавление статьи'})

А сам шаблон addpage.html определим так:

{% extends 'base.html' %}
 
{% block content %}
<h1>{{title}}</h1>
Содержимое страницы
{% endblock %}

Теперь, при обновлении увидим полноценную страницу для добавления нового поста.

Давайте вначале сформируем форму вручную. Запишем в PyCharm вместо тега <p> и строки слово form. Нажмем Tab и сразу появится тег form в виде:

<form action=""></form>

Внутри этого тега для примера запишем следующий тег input:

<form action="">
    <input type="text">
</form>

Обновим страницу и увидим в окне браузера на странице поле ввода. Как вы догадались, оно текстовое, так как имеет атрибут type="text".

Давайте добавим еще несколько полей, например:

<form action="">
    <input type="text">
    <input type="checkbox">
    <input type="number">
    <input type="password">
</form>

В действительности, типов этих полей огромное количество. Все их можно посмотреть в справочнике или на специализированных сайтах. Довольно неплохой ресурс можно найти по этой ссылке:

https://www.w3schools.com/html/html_forms.asp

Чтобы добавить пояснения к этим полям, обычно, используют тег label следующим образом:

<form action="">
    <label for="id_1">Текст: </label><input type="text" id="id_1">
    <label for="id_2">Отметка: </label><input type="checkbox" id="id_2">
    <label for="id_3">Число: </label><input type="number" id="id_3">
    <label for="id_4">Пароль: </label><input type="password" id="id_4">
</form>

И, давайте, расположим их в столбик, каждый на своей строке. Я сделаю это с помощью тега абзаца p:

<form action="">
    <label for="id_1">Текст: </label><input type="text" id="id_1"></p>
    <label for="id_2">Отметка: </label><input type="checkbox" id="id_2"></p>
    <label for="id_3">Число: </label><input type="number" id="id_3"></p>
    <label for="id_4">Пароль: </label><input type="password" id="id_4"></p>
</form>

У нас с вами получилось уже нечто вразумительное. Но форма пока не функциональна. Чтобы она отправляла данные на сервер, необходимо добавить кнопку специального типа submit:

<form action="">
    ...
    <button type="submit">Отправить</button></p>
</form>

(Параметр type со значением submit внутри формы у кнопки можно и не прописывать, но так понятнее ее назначение.)

Перейдем в форму, нажмем на эту кнопку и наша страница обновилась. Кроме того, в URL адресе появился знак вопроса. Он символизирует начало строки с данными GET-запроса. Но почему сейчас никаких данных нет? Дело в том, что у каждого поля дополнительно нужно прописать специальный атрибут name с именем параметра поля. Сделаем это:

name="field_text"
name="field_check"
name="field_num"
name="field_psw"

Теперь, при отправке формы GET-запрос стал принимать вид:

http://127.0.0.1:8000/addpage/?field_text=&field_num=&field_psw=

То есть, здесь после знака вопроса через амперсанд идут данные в формате ключ=значение. Так как значений нет, то просто перечисляются поля.

Давайте введем какие-либо данные в форму и снова отправим их. Получим следующий вид GET-запроса:

http://127.0.0.1:8000/addpage/?field_text=aaa&field_check=on&field_num=123&field_psw=asd

Эти данные сервер передает во фреймворк Django, он их упаковывает в словарь request.GET и там мы получаем к ним доступ. Давайте для примера я поставлю точку останова в функции обработчике addpage() данной страницы и, смотрите, в словаре request.GET, как раз находится вся переданная информация из формы. Причем, данные отправляются в функцию addpage() по той причине, что мы в атрибуте action тега form ничего не указали. Если, например, мы там укажем слеш:

<form action="/">
...
</form>

то обработчиком формы будет считаться главная страница. Но, нам это не нужно и я оставлю пустые кавычки.

У тега form есть еще один важный атрибут method, который определяет тип запроса для отправки данных формы. По умолчанию используется метод GET, то есть, GET-запрос, что мы только что и видели. Но этот запрос плох тем, что все данные пользователи видят в строке браузера. Например, так отправлять логины, пароли и другую служебную информацию не стоит. Вместо этого лучше воспользоваться другим типом запроса, который называется POST:

<form action="" method="post">
...
</form>

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

{% csrf_token %}

Теперь отправка данных работает без проблем и в словаре request.POST мы можем все их видеть.

В рамках данного курса я не буду углубляться в построение форм на уровне HTML-документа. Введение в эту тему уже есть в курсе по HTML и CSS. И я полагаю, что вы уже владеете этим материалом. Если нет, то посмотрите. Он небольшой и несложный:

https://www.youtube.com/playlist?list=PLA0M1Bcd0w8wRiyGX_9y-fUiBPi1vqaTb

На следующем занятии мы продолжим эту тему и посмотрим, как можно автоматизировать формирование HTML-форм с помощью классов форм фреймворка Django.

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

Видео по теме