Третий этап
В заключительной части туториала мы рассмотрим основные аспекты работы с формами WTForms, разработаем функции CRUD и напишем функцию для экспорта информации из базы данных. Код для первого и второго этапов разработки есть здесь.
Валидация форм WTForms
Для получения пользовательских данных со стороны фронтенда в Flask-приложениях обычно используют формы WTForms. Эти формы «из коробки» предоставляют отличные опции для валидации введенных данных. Расширение функциональности форм за счет макросов и дополнительных валидаторов тоже не вызывает никаких сложностей, как мы это увидим позже.
Для взаимодействия с приложением нам потребуются две формы – BookForm и UpdateBook. Первая отвечает за создание новой карточки, вторая – за редактирование существующей записи. Обложки книг можно загружать как во время создания карточки, так и после – в процессе редактирования. Обратите внимание на формат использования валидаторов:
- DataRequired – не даст отправить форму, если поле останется незаполненным.
- Length(min=5, max=100) – минимальная длина строки в поле – 5 символов, максимальная – 100.
- FileAllowed(['jpg', 'png']) – разрешает присоединять к форме только изображения .jpg и .png.
- NumberRange(min=1, max=5)]) – обеспечивает ввод оценки для книги в диапазоне от 1 до 5 включительно.
Кроме стандартных валидаторов, мы будем использовать один пользовательский:
Этот валидатор предотвращает создание карточки с названием книги, которое уже есть в базе. Без него приложение остановится с ошибкой:
Эта ошибка связана с атрибутом unique=True
столбца title
и ее проще предотвратить, чем обрабатывать. Но обработку мы тоже рассмотрим ниже – она будет реализована в функции представления.
Шаблоны для форм
Формам для создания и редактирования записей нужны шаблоны. Здесь есть код для create.html и edit.html. Шаблон create.html предусматривает вывод ошибок:
Для ввода и обработки разных типов информации используются различные классы:
- class="form-control-label" – однострочное текстовое поле;
- class="form-control-textarea" – многострочное текстовое поле;
- class="form-control-number" – ввод цифр;
- class="form-control-file" – выбор файла.
В шаблоне edit.html используется предварительное заполнение формы, уже внесенной в карточку информацией, – чтобы пользователю было проще ее редактировать. Эту информацию отправляет в форму функция edit
, которую мы рассмотрим чуть позже. Для генерации шаблона нужен вспомогательный макрос – он находится в файле formhelpers.html. Этот файл необходимо поместить в папку /templates вместе с обычными шаблонами. В шаблоне для редактирования есть блок для вывода сообщений об ошибках базы данных, получаемых от Flask и SQLAlchemy (остальные ошибки валидации обрабатывает WTForms):
Примечание: для создания и редактирования записей при желании можно использовать один и тот же шаблон. Если вставить в шаблон edit.html код из create.html, он точно так же получит существующие данные из функции представления. Кроме того, часто для редактирования и создания записей используют один и тот же код в одном и том же файле. В данном случае мы используем рендеринг формы редактирования с помощью макроса из _formhelpers.html просто в образовательных целях.
Обработка данных из форм
Для создания, редактирования и удаления записей нам нужно написать соответствующие функции в файле routes.py. Кроме того, нужно сделать функцию для безопасной загрузки изображений. Начнем с импорта форм и модуля Pillow, который обеспечит автоматическое сжатие обложек и сохранение файлов в нужную папку uploads:
Фласку тоже потребуется импорт дополнительных модулей – flash, url_for и redirect. Pillow нужны модули os и secrets, а для обработки ошибок базы понадобится IntegrityError.
Функция для обработки и сохранения обложек книг выглядит так:
Функция создания новых записей выглядит так:
Если во время создания новой записи обложка не будет загружена, в карточке будет отображаться изображение по умолчанию. Как видно по приведенному выше коду, в базе данных сохраняется только имя файла изображения, сами картинки загружаются в папку uploads.
Функция для редактирования отправляет в форму уже существующие в карточке данные, чтобы форма не была пустой, и обрабатывает ошибку IntegrityError
– она возникает, если в процессе редактирования существующей карточки пользователь вводит название книги, которое уже есть в базе:
Удалить карточку книги проще простого:
Для подтверждения удаления карточки будет использоваться всплывающее окно – код для этого уже есть в шаблонах. Осталось добавить в base.html, index.html, book.html, best.html и thrillers.html ссылки на соответствующие операции по созданию, редактированию и удалению карточек:
Теперь карточки можно удалять:
Редактировать:
И создавать:
Экспорт данных из базы
Информацию из наполненной базы данных можно экспортировать самыми разными способами. Мы рассмотрим простой и практичный метод, который не требует установки никаких дополнительных модулей. Файл json, который мы использовали в первой части туториала, был создан именно таким способом.
Для реализации метода нужно внести небольшое дополнение в файл моделей /reader/models.py и написать функцию для /reader/routes.py. Сначала дополним класс Book
:
Эти данные будут экспортированы. Если не нужен ID записи, или время создания, или еще что-нибудь – соответствующие строки можно удалить.
Добавим импорт jsonify
и функцию экспорта в /reader/routes.py:
В файл __init__.py добавим параметр app.config['JSON_AS_ASCII'] = False
– иначе jsonify вместо кириллицы экспортирует абракадабру.
Все готово: если перейти по адресу http://localhost:8000/export/, можно увидеть все содержимое базы в виде словаря:
На этом работа над приложением закончена. Очевидно, что функциональность SQLAlchemy значительно упростила процесс разработки. И хотя SQLAlchemy – не единственная библиотека, предоставляющая Flask-приложениям все преимущества ORM, ее уверенно можно назвать самой понятной и гибкой, чем и объясняется ее популярность. Напоминаем, что финальная версия кода находится здесь.
Комментарии