Рубрики
Без рубрики

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

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

Автор оригинала: Ruslan Hasanov.

Вступление

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

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

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

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

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

Мы будем использовать версию колбы 1.1.2 и колба-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 в конфигурацию нашего приложения объекта.

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

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

Давайте создадим и добавим форму к нашему текущему 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'))

# ...

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

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

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

Проверка Формы Колбы С Помощью Flask-WTForms

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

# ...

@app.route('/', methods=('GET', 'POST'))
def index():
    form = GreetUserForm()
    if form.validate_on_submit():
        return f'''

Welcome {form.username.data}

''' 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.csrf_token() }} {{ form.username }}
{{ form.submit(class="btn btn-primary")}}

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

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

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

$ FLASK_ENV=development flask run

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

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

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

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

Успешная подача формы с именем пользователя

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

Успешная подача формы без имени

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

Мы импортируем один из встроенных методов проверки WTForms: Data Required() из 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 в виде списка. Это говорит нам о том, что у нас может быть несколько валидаторов для каждого поля.

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

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

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

Проверка HTML-кода формы, чтобы увидеть

Таким образом, 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

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

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

 {% for field, errors in form.errors.items() %}
    
        {{ ', '.join(errors) }}
    
{% endfor %}

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

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

По любой причине, если нам нужно ограничить максимальную длину наших полевых данных, мы можем сделать это, передав параметр 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'))

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

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

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

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

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

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

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'))

# ...    

У нас есть четыре различных поля в наших формах. Последняя – это обычная кнопка отправки. Мы использовали String Field для получения строковых входных данных от пользователей, таких как username и email . С другой стороны, поле Password скрывает текст пароля на интерфейсе. BooleanField отображается как флажок на интерфейсе, так как он содержит только значения True (Checked) или False (Unchecked).

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

Registration Form

{% for field, errors in form.errors.items() %} {{ ', '.join(errors) }} {% endfor %}
{{ form.csrf_token() }}
{{ form.username.label }} {{ form.username(class="form-control") }}
{{ form.email.label }} {{ form.email(class="form-control") }}
{{ form.password.label }} {{ form.password(class="form-control") }}
{{ form.confirm_password.label }} {{ form.confirm_password(class="form-control") }}
{{ form.receive_emails.label }}
{{ form.submit(class="btn btn-primary")}}

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

Корректное отображение регистрационной формы пользователя

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

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

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

WTForms позволяет нам добавлять пользовательские валидаторы, добавляя валидацию метод в нашу Регистрационную форму пользователя класс. Давайте реализуем эту пользовательскую проверку в нашей форме, добавив метод 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 , которое будет содержать исключенный символ – ‘%’.

Пользователь от невозможности проверки из-за нашей пользовательской проверки

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

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

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

Вывод

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

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