Django — объект формы и Generic Views

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

Для этого были придуманы веб-формы — специальные компоненты HTML-страниц, в которых предусмотрены разнообразные поля ввода: текстовые поля, чекбоксы (поля с галочками), наборы radiobuttons (они дают возможность выбрать один вариант из нескольких).

HTML-форма может выглядеть так:

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

А что внутри?

HTML-код этой формы:

<!-- Форма оборачивается тегом form, 
     в открывающем теге указывается тип и адрес запроса для отправки данных -->
<form method="post" action="/user-form/">
  <!-- Тег label - заголовок для поля ввода -->
  <label>Введите имя:</label>
  <!-- type - тип поля ввода (здесь - текстовое поле), 
       name - имя поля в POST-запросе, в котором будет отправлена информация,
       введённая пользователем -->
  <input type="text" name="first_name">
  <br><br>
  <label>Введите фамилию:</label>
  <input type="text" name="last_name">
  <br><br>  
  <input type="checkbox" name="is_human"> Я человек
  <br><br>
  Опишите себя (выберите вариант)<br>
  <input type="radio" name="quality" value="good"> Хороший<br>
  <input type="radio" name="quality" value="bad"> Плохой<br>
  <input type="radio" name="quality" value="ugly"> Злой
  <br><br>
  <!-- Этот код отрисует кнопку с надписью "Отправить" -->
  <input type="submit" value="Отправить">
</form> 

В открывающем теге формы указано, что после нажатия на кнопку «Отправить»

  • данные будут отправлены POST-запросом: method="post";
  • POST-запрос будет отправлен на адрес /user-form/action="/user-form/".

Названиями полей в POST-запросе будут значения атрибутов name полей ввода формы, а значениями полей POST-запроса — данные, введённые или выбранные пользователем:

{'first_name': 'Клинт',
'last_name': 'Иствуд',
'is_human': True,
'quality': 'good'
} 

На сервер придёт обычный POST-запрос, и его можно обработать: сохранить полученные данные в БД, проверить права доступа пользователя или сделать что-то ещё.

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

Объект формы

Для работы с веб-формами в Django есть несколько предустановленных классов, пользовательские классы наследуют от них. Классы Form и ModelForm упрощают создание веб-форм и обработку данных, полученных из них.

  • объект класса формы можно передать в контекст страницы — и шаблонизатор автоматически сгенерирует веб-форму;
  • при получении POST-запроса можно создать объект формы, передать в него данные запроса — и обработать их, используя встроенные методы класса формы.

Классы форм описывают в файле forms.py. Данные, полученные из веб-формы, могут обрабатываться по-разному: например, форма для публикации поста в блоге должна добавлять новую запись в БД, а форма для почтовой связи с другим пользователем сайта может просто отправлять письмо, не сохраняя данные в базу.

Самая востребованная задача при работе с формами — добавлять или редактировать информацию в базе данных. Для этого есть специальный класс форм: ModelForm.

Форма на основе модели: класс ModelForm

Экземпляр класса ModelForm можно напрямую связать с нужной моделью; форма автоматически возьмёт из модели поля и определит их свойства.

Если объект формы передать в контекст страницы — будет сгенерирована веб-форма с полями ввода, соответствующими полям модели.

При получении данных из веб-формы объект формы проверит полученную информацию и запишет её в связанную модель.Всё это умеет класс ModelForm: быстро, просто, надёжно — и без лишнего кода.В общем виде формы на основе моделей создаются так:

  1. Создаётся (или выбирается существующая) модель.
  2. Создаётся класс формы (наследуется от ModelForm), в нём указывается, с какой моделью будет работать эта форма.
  3. Объект формы (экземпляр, созданный на основе класса формы) передаётся в специальный view-класс.
  4. View-класс передаёт объект формы в шаблон, создаёт и возвращает пользователю страницу с веб-формой.

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

# library/models.py
from django.db import models    
    
# Создадим модель, в которой будем хранить данные о книгах
class Book(models.Model):
    name = models.CharField(max_length=200)   # Название
    isbn = models.CharField(max_length=100)   # Индекс издания
    pages = models.IntegerField(min_value=1)  # Количество страниц 

Создаём класс формы на основе этой модели; унаследуем его от ModelForm:

# library/forms.py
from django import forms  # Импортируем модуль forms, из него возьмём класс ModelForm

from .models import Book  # Импортируем модель, чтобы связать с ней форму

class BookForm(forms.ModelForm):
    class Meta:
        # Эта форма будет работать с моделью Book
        model = Book

        # Здесь перечислим поля модели, которые должны отображаться в веб-форме;
        # при необходимости можно вывести в веб-форму только часть полей из модели.
        fields = ('name', 'isbn', 'pages') 

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

View-функции и view-классы

При обращении к какому-нибудь URL Django-проекта запрос передаётся в urls.py, и там специальный обработчик path() вызывает view-объект, передавая ему в качестве аргумента объект типа request, а на выходе ожидает объект типа response.

Вызываемым объектом может быть view-функция, а может — специальный view-класс.

  • View-функция, «функции представления» (от англ. view, «отображение, представление») или просто «представление». Это самый простой тип view-объектов. Функция получает на вход стандартный объект request и возвращает объект типа response.Объекты response могут быть созданы встроенными функциями-помощниками, например, функцией render(). Вызов view-функции: path('any_url/', my_view)
  • View-классы или class-based view («представление, основанное на классе», «представление-класс»), как и view-функции, обрабатывают запрос и возвращают объект типа response. Такие классы должны наследоваться от специальных встроенных классов Generic Views*.*
    В path() view-классы вызываются через метод as_view():path('any_url/', ClassName.as_view())

Generic Views

Generic Views (англ. «общий вид» или «базовое представление») — это встроенные в Django view-классы, созданные для решения стандартных задач. На основе Generic Views создают классы-наследники — view-классы, обладающие свойствами и методами родительского Generic Views; это классическое ООП в действии.Можно не писать собственный обработчик, а создать свой view-класс, унаследовав его от подходящего Generic View — и обработчик готов, остаётся вызвать его в urls.py.

View-класс для форм: CreateView

Для обработки формы BookForm возьмём дженерик CreateView, он обрабатывает формы и на основе полученных из формы данных создаёт новые записи в БД.

# library/views.py
from django.views.generic.edit import CreateView
from .forms import BookForm


class BookView(CreateView):  # Создаём свой класс, наследуем его от CreateView
    # C какой формой будет работать этот view-класс
    form_class = BookForm    

    # Какой шаблон применить для отображения веб-формы
    template_name = 'library/new_book.html'  

    # Куда переадресовать пользователя после того, как он отправит форму
    success_url = '/thankyou/'   

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

# library/urls.py

#  теперь из файла urls.py для пути new_book/ 
#  можно вызвать метод as_view() класса BookView

urlpatterns = [
    # ...
    path('new_book/', views.BookView.as_view(), name='new_book')
] 

В зависимости от типа запроса view-класс BookView будет вести себя по-разному.

  • При GET-запросе (например, пользователь в браузере перешёл по адресу new_book/)
    • view-класс BookView получит запрос и передаст в шаблон library/new_book.html объект формы (экземпляр класса BookForm) с полями 'name''isbn' и 'pages';
    • шаблонизатор сгенерирует HTML-код формы;
    • веб-страница с формой будет отправлена пользователю.
  • При POST-запросе (если пользователь заполнил веб-форму и нажал кнопку «Отправить»)
    • POST-запрос приходит во view-класс BookView,
    • данные запроса проверяются на соответствие требованиям модели (например, содержимое поля name не должно превышать 200 символов, а поле pages должно быть числом, не меньшим единицы),
    • если проверка прошла успешно — будет создана новая запись в базе данных.

Шаблон для отрисовки формы

Осталось подготовить HTML-шаблон. View-класс передаёт в него объект формы form, надо вывести форму на страницу.

Объект form содержит список полей веб-формы, и тег шаблона {{ form.as_p }} «обернёт» каждое поле в HTML-тег <p>: в результате поля формы будут разбиты построчно, это будет выглядеть приличнее, чем если бы они склеились в одну строку.

<form method="post" action="{% url 'library:new_book' %}">
  {{ form.as_p }}
  <input type="submit" value="Отправить">
</form> 

После рендеринга страницы получится такой HTML:

<form method="post" action="/new_book/">
  <p><label for="id_name">name:</label>
     <input id="id_name" type="text" name="name" maxlength="200" required></p>
  <p><label for="id_isbn">isbn:</label>
     <input id="id_isbn" type="text" name="isbn" maxlength="100" required></p>
  <p><label for="id_pages">pages:</label>
     <input id="id_pages" type="number" name="pages" required></p>
  <input type="submit" value="Отправить">
</form> 

Готово: в базу данных можно добавлять новые записи через веб-форму, размещённую на странице сайта.При отправке данных происходит примерно такая цепочка событий:GET-запрос к странице → заполнение HTML-формы → POST-запрос → обработка во view-классе → ORM → модель → БД





Добавить комментарий

;-) :| :x :twisted: :smile: :shock: :sad: :roll: :razz: :oops: :o :mrgreen: :lol: :idea: :grin: :evil: :cry: :cool: :arrow: :???: :?: :!: