Проверка формы флакона с помощью WTForms

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

Вступление

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

Попытка обработать непроверенные вводимые пользователем данные может вызвать неожиданные / необработанные ошибки, если не сбой сервера. В этом контексте проверка данных означает проверку входных данных и проверку их соответствия определенным ожиданиям или критериям. Проверка данных может выполняться как на передней, так и на задней стороне.

В этом руководстве мы узнаем, как проверять ввод данных пользователем в формах Flask с помощью расширения Flask-WTForms.

К концу этого руководства у нас будет следующая форма регистрации пользователя с критериями проверки:

Регистрационная форма сподтверждением

Мы будем использовать Flask версии 1.1.2 и Flask-WTF версии 0.14.3 .

Настраивать

Хотя в этом нет необходимости, мы рекомендуем вам создать виртуальную среду, чтобы следовать:

 $ mkdir flask-form-validation 
 $ cd flask-form-validation 
 $ python3 -m venv . 
 $ . bin/activate 

В вашей активированной виртуальной среде мы установим наши пакеты, набрав:

 $ pip install Flask Flask-WTF 

Обратите внимание, что если вы хотите использовать проверку электронной почты, вам также необходимо установить email_validator (текущая версия - 1.1.1 ):

 $ pip3 install email_validator 

Теперь создадим необходимые нам файлы. Мы начнем с создания базового app.py , который для простоты будет содержать наше приложение Flask, маршруты и формы:

 from flask import Flask, render_template 
 
 app = Flask(__name__, template_folder='.') 
 app.config['SECRET_KEY']='LongAndRandomSecretKey' 

Мы создали объект Flask и установили template_folder в текущую папку. Затем мы присвоили объект Flask переменной app Мы добавили SECRET_KEY в конфигурацию объекта app

SECRET_KEY обычно используется для шифрования соединений с базой данных и сеансов браузера. WTForms будет использовать SECRET_KEY как соль для создания токена CSRF. Вы можете узнать больше о CSRF на этой вики-странице.

Если ваше приложение уже использует SECRET_KEY для других целей, вы можете создать новую конфигурацию для WTForms. В этом случае вы можете установить конфигурацию WTF_CSRF_SECRET_KEY

Давайте создадим и добавим форму в наш текущий app.py :

 from flask import Flask, render_template 
 from flask_wtf import FlaskForm 
 from wtforms import StringField, SubmitField 
 
 class GreetUserForm(FlaskForm): 
 username = StringField(label=('Enter Your Name:')) 
 submit = SubmitField(label=('Submit')) 
 
 # ... 

Наш простой класс GreetUserForm StringField . Как следует из названия, это поле ожидает и вернет строковое значение (вы всегда можете преобразовать этот ввод в другие типы данных по мере необходимости). Имя поля - username , и мы будем использовать это имя для доступа к данным элемента формы.

Параметры label - это то, что будет отображаться на нашей странице, чтобы пользователи понимали, какие данные захватывает элемент формы. У нас также есть submit , которая попытается отправить форму, если все поля соответствуют нашим критериям проверки.

Теперь, когда мы настроены, давайте использовать WTForms для проверки наших данных!

Проверка формы Flask с помощью Flask-WTForms

Начнем с создания маршрута для отображения и обработки нашей формы:

 # ... 
 
 @app.route('/', methods=('GET', 'POST')) 
 def index(): 
 form = GreetUserForm() 
 if form.validate_on_submit(): 
 return f'''<h1> Welcome {form.username.data} </h1>''' 
 return render_template('index.html', form=form) 

В нашем маршруте есть методы GET и POST Метод GET отображает форму, тогда как POST обрабатывает данные формы при отправке. Мы устанавливаем URL-путь на / или корневой URL-адрес, чтобы он отображался как домашняя страница нашего веб-приложения. Мы визуализируем index.html и передаем form в качестве параметра.

Сделаем паузу и внимательно рассмотрим эту строку: if form.validate_on_submit(): Это правило гласит: «Если метод запроса

  • POST и если поля формы действительны, продолжайте». Если введенная нами форма соответствует нашим критериям проверки, на следующей странице будет отображено простое приветственное сообщение с именем пользователя. Обратите внимание, что здесь мы использовали имя поля ( username ) для доступа к входным данным.

Чтобы увидеть форму, нам нужно создать шаблон index.html Создайте файл и добавьте в него следующий код:

 <form method="POST" action=""> 
 <div class="form-row"> 
 <div class="form-group col-md-6"> 
 {{ form.csrf_token() }} 
 <label for=""> {{ form.username.label }}</label> 
 {{ form.username }} 
 </div> 
 <div class="form-group"> 
 {{ form.submit(class="btn btn-primary")}} 
 </div> 
 </div> 
 </form> 

Мы используем наш form для передачи элементов WTform в Jinja2 - синтаксический анализатор шаблонов для Flask.

Примечание : csrf_token автоматически генерируется WTForms и изменяется каждый раз при отрисовке страницы. Это помогает нам защитить наш сайт от атак CSRF. По умолчанию это скрытое поле. Вы также можете использовать {{ form.hidden_field() }} для отображения всех скрытых полей, включая токен CSRF, но это не рекомендуется.

Теперь давайте перейдем к нашему терминалу, чтобы запустить приложение Flask, набрав:

 $ FLASK_ENV=development flask run 

Для удобства мы установили для FLASK_ENV значение «разработка» во время разработки. Это позволяет приложению перезагружаться каждый раз, когда мы нажимаем «Сохранить». Для Windows вам, возможно, придется использовать set FLASK_ENV=development в вашем терминале / консоли перед запуском вашего приложения flask.

Вот что мы увидим, если перейдем на localhost:

Запуск приложения Flask сформой{.ezlazyload}

Введите имя в поле ввода и отправьте форму. Вы увидите приветственное сообщение, которое мы определили в нашем маршруте:

Успешная отправка формы с именемпользователя{.ezlazyload}

Работает как положено. Но что, если мы ничего не вводим в поле ввода? Он все равно подтвердит форму:

Успешная отправка формы безимени{.ezlazyload}

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

Мы импортируем один из встроенных методов проверки WTForms: DataRequired() из wtforms.validators и передадим его в наше поле username

 # ... 
 from wtforms.validators import ValidationError, DataRequired 
 
 class GreetUserForm(FlaskForm): 
 username = StringField(label=('Enter Your Name:'), 
 validators=[DataRequired()]) 
 submit = SubmitField(label=('Submit')) 
 
 # ... 

Обратите внимание, что мы передаем validators в виде списка. Это говорит нам о том, что у нас может быть несколько валидаторов для каждого поля.

Теперь, когда мы используем DataRequired() , username не будет проверяться, если нет входных данных:

Всплывающая подсказка отображается пользователю, когда данные формыпусты{.ezlazyload}

Фактически, если мы щелкнем правой кнопкой мыши и проверим элемент формы, мы увидим, что WTForms автоматически добавил required атрибут в поле ввода:

Проверка HTML-кода формы на предмет «обязательного» атрибута поляввода.{.ezlazyload}

Таким образом, WTForms добавляет базовую проверку внешнего вида в наше поле формы. Вы не сможете отправить эту форму без username даже если попытаетесь опубликовать форму с помощью таких инструментов, как cURL или Postman.

Теперь предположим, что мы хотим установить новое правило проверки, которое будет разрешать только имена длиной не менее 5 символов. Мы можем использовать валидатор Length() с параметром min

 # ... 
 from wtforms.validators import ValidationError, DataRequired, Length 
 
 class GreetUserForm(FlaskForm): 
 username = StringField(label=('Enter Your Name:'), 
 validators=[DataRequired(), Length(min=5)]) 
 submit = SubmitField(label=('Submit')) 
 
 # ... 

Если мы попытаемся отправить форму с входными данными длиной менее 5 символов, критерии проверки не будут выполнены, и отправка завершится ошибкой:

Ошибка проверкиwtforms{.ezlazyload}

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

В нашем index.html прямо под {{ form.username }} добавьте следующий цикл for Jinja2 для отображения ошибок:

 {% for field, errors in form.errors.items() %} 
 <small class="form-text text-muted "> 
 {{ ', '.join(errors) }} 
 </small> 
 {% endfor %} 

Теперь наша форма может отображать чистые ошибки проверки:

Ошибки отрисовки формы для короткого именипользователя{.ezlazyload}

По любой причине, если нам нужно ограничить максимальную длину данных нашего поля, мы можем сделать это, передав параметр max валидатору Length() Также можно настроить сообщение об ошибке, передав необязательный message с настраиваемой строкой ошибки.

Давайте соответствующим образом обновим поле username

 # ... 
 
 class GreetUserForm(FlaskForm): 
 username = StringField(label=('Enter Your Name:'), 
 validators=[DataRequired(), 
 Length(min=5, max=64, message='Name length must be between %(min)d and %(max)dcharacters') ]) 
 submit = SubmitField(label=('Submit')) 
 
 # ... 

Ошибки отрисовки формы для короткого имени пользователя снастраиваемымсообщением{.ezlazyload}

Дополнительные поля и валидаторы WTForms в форме регистрации пользователя

В нашей текущей форме есть одно поле, которое довольно скучно. WTForms предоставляет обширные критерии проверки формы и множество полей формы, поэтому давайте воспользуемся этим и создадим что-то с практическим применением.

Мы создадим форму регистрации пользователя и будем использовать встроенные валидаторы WTForms.

Мы будем использовать DataRequired() для полей, которые мы хотим убедиться, что пользователь заполняет их. Мы проверим минимальную и максимальную длину полей с помощью Length() , подтвердим электронные письма с помощью Email() и проверим если два поля содержат одинаковые данные с валидатором EqualTo()

Удалите GreetUserForm и замените начало кода нашей новой формой:

 from flask import Flask, render_template 
 from flask_wtf import FlaskForm 
 from wtforms import StringField, PasswordField, BooleanField, \ 
 SubmitField 
 from wtforms.validators import ValidationError, DataRequired, \ 
 Email, EqualTo, Length 
 
 class CreateUserForm(FlaskForm): 
 username = StringField(label=('Username'), 
 validators=[DataRequired(), 
 Length(max=64)]) 
 email = StringField(label=('Email'), 
 validators=[DataRequired(), 
 Email(), 
 Length(max=120)]) 
 password = PasswordField(label=('Password'), 
 validators=[DataRequired(), 
 Length(min=8, message='Password should be at least %(min)d characters long')]) 
 confirm_password = PasswordField( 
 label=('Confirm Password'), 
 validators=[DataRequired(message='*Required'), 
 EqualTo('password', message='Both password fields must be equal!')]) 
 
 receive_emails = BooleanField(label=('Receive merketting emails.')) 
 
 submit = SubmitField(label=('Submit')) 
 
 # ... 

В наших формах есть четыре разных поля. Последняя - обычная кнопка отправки. Мы использовали StringField для получения строковых данных от пользователей, таких как username и email . С другой стороны, PasswordField скрывает текст пароля во внешнем интерфейсе. BooleanField отображается как флажок во внешнем интерфейсе, поскольку он содержит только значения True (отмечен) или False (не отмечен).

Нам нужно изменить index.html чтобы отобразить наши новые поля формы:

 <div class="container"> 
 <h2>Registration Form</h2> 
 {% for field, errors in form.errors.items() %} 
 {{ ', '.join(errors) }} 
 {% endfor %} 
 <form class="form-horizontal" method="POST" action=""> 
 {{ form.csrf_token() }} 
 <div class="form-group"> 
 {{ form.username.label }} 
 {{ form.username(class="form-control") }} 
 </div> 
 <div class="form-group"> 
 {{ form.email.label }} 
 {{ form.email(class="form-control") }} 
 </div> 
 <div class="form-group"> 
 {{ form.password.label }} 
 {{ form.password(class="form-control") }} 
 </div> 
 <div class="form-group"> 
 {{ form.confirm_password.label }} 
 {{ form.confirm_password(class="form-control") }} 
 </div> 
 <div class="form-group"> 
 {{ form.receive_emails.label }} 
 </div> 
 <div class="form-group"> 
 {{ form.submit(class="btn btn-primary")}} 
 </div> 
 </form> 
 </div> 

Наши поля формы отображаются правильно, как вы можете видеть:

Форма регистрации пользователя отображаетсяправильно{.ezlazyload}

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

Создание собственных пользовательских валидаторов

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

WTForms позволяет нам добавлять собственные валидаторы, добавляя метод валидации в наш класс UserRegistrationForm Давайте внедрим эту настраиваемую проверку в нашу форму, добавив метод validate_username() прямо под кнопкой submit

 # ... 
 
 class UserRegistrationForm(FlaskForm): 
 # ... 
 submit = SubmitField(label=('Submit')) 
 
 def validate_username(self, username): 
 excluded_chars = " *?!'^+%&/()=}][{$#" 
 for char in self.username.data: 
 if char in excluded_chars: 
 raise ValidationError( 
 f"Character {char} is not allowed in username.") 
 
 # ... 

Мы можем добавить столько методов проверки, сколько захотим. WTForms будет запускать методы проверки автоматически после определения.

Класс ValidationError дает нам удобный способ определить наше настраиваемое сообщение проверки. Обратите внимание, что вам нужно будет импортировать его из wtforms.validators прежде чем использовать.

Давайте протестируем этот новый метод, введя правильные данные во все поля, кроме поля имени username , которое будет содержать исключенный символ - «%».

Форма пользователя не проходит проверку из-за нашей настраиваемойпроверки{.ezlazyload}

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

Вы можете использовать внешние библиотеки, вашу базу данных или API для объединения с WTForms и для проверки входящих входных данных. Если вы хотите захватить {{ form.some_field.data }} и записать в базу данных или запросить из нее, используйте валидаторы WTForms, чтобы гарантировать безопасность сохранения.

Примечание . Мы исключили большинство кодов HTML, поскольку они не имеют прямого отношения к нашему руководству. Полный код будет доступен в этом репозитории GitHub , если вы захотите оформить заказ.

Заключение

Проверка данных - одна из самых важных частей веб-приложений Flask. Flask-WTforms предоставляет очень мощные и простые в освоении способы обработки данных форм.

Теперь, когда вы знаете основы проверки данных с помощью Flask-WTF, вы можете продолжить и применить свою собственную логику проверки и / или реализовать свои собственные методы как для безопасности, так и для улучшения взаимодействия с пользователем.

comments powered by Disqus