Flask Series (9) - Flask-WTF

Posted by brownka on Sun, 16 Jun 2019 01:25:21 +0200

Flask-WTF

Flask-WTF is a third-party library that simplifies WTForms operations. The two main functions of the WTForms form are to verify the validity of the data submitted by the user and to render the template. Of course, there are also some other functions: CSRF protection, file upload and so on. Installing Flask-WTF also installs WTForms by default, so use the following commands to install Flask-WTF:

pip install flask-wtf

Form validation: After installing Flask-WTF. Let's take a look at the first function, which is to do data validation with forms. Now there is a forms.py file, and then create a RegistForm registration validation form in it:

class RegistForm(Form):
    name = StringField(validators=[length(min=4,max=25)])
    email = StringField(validators=[email()])
    password = StringField(validators=[DataRequired(),length(min=6,max=10),EqualTo('confirm')])
    confirm = StringField()

It specifies the parameters that need to be uploaded and the validator, such as name, should be between 4 and 25. email must meet the format of the mailbox. The password length must be between 6 and 10 and should be equal to confirm in order to be validated.

After the form is written, the register. HTML file follows:

<form action="/regist/" method="POST">
<table>
<tr>
<td>User name:</td>
<td><input type="text" name="name"></td>
</tr>
<tr>
<td>Mailbox:</td>
<td><input type="email" name="email"></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" name="password"></td>
</tr>
<tr>
<td>Confirm password:</td>
<td><input type="password" name="confirm"></td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Submission"></td>
</tr>
</table>
</form>

Look again at the view function regist er:

@app.route('/regist/',methods=['POST','GET'])
def regist():
    form = RegistForm(request.form)
    if request.method == 'POST' and form.validate():
        user = User(name=form.name.data,email=form.email.data,password=form.password.data)
        db.session.add(user)
        db.session.commit()
        return u'login was successful!'
    return render_template('regist.html')

RegistForm passes request.form in for initialization, and determines whether form.validate returns the data submitted by the user to satisfy the validation of the form.

Rendering template: Form can also render template, so that you can write less lost code, such as rewriting the above example, RegistForm form code is as follows:

class RegistForm(Form):
    name = StringField(u'User name:',validators=[length(min=4,max=25)])
    email = StringField(u'Mailbox:'validators=[email()])
    password = StringField(u'Password:',validators=[DataRequired(),length(min=6,max=10),EqualTo('confirm')])
    confirm = StringField(u'Confirm password:')

The first location parameter has been added to do tag prompting in html files.

In the view function in app, modify it to read as follows:

@app.route('/regist/',methods=['POST','GET'])
def regist():
    form = RegistForm(request.form)
    if request.method == 'POST' and form.validate():
        user = User(name=form.name.data,email=form.email.data,password=form.password.data)
        db.session.add(user)
        db.session.commit()
        return u'login was successful!'
    return render_template('regist.html',form=form)

The only difference is that form form parameters are passed in when rendering the template so that form variables can be used in the template.

Next, look at the register. HTML file:

<form action="/regist/" method="POST">
<table>
<tr>
<td>{{ form.name.label }}</td>
<td>{{ form.name() }}</td>
</tr>
<tr>
<td>{{ form.email.label }}</td>
<td>{{ form.email() }}</td>
</tr>
<tr>
<td>{{ form.password.label }}</td>
<td>{{ form.password() }}</td>
</tr>
<tr>
<td>{{ form.confirm.label }}</td>
<td>{{ form.confirm() }}</td>
</tr>
<tr>
<td></td>
<td><input type="submit" value="Submission"></td>
</tr>
</table>
</form>

Field Common Parameters: When using Field, it is often necessary to pass in some parameters. The following will explain some commonly used parameters:
* label (first parameter): the text of Field's label.
* validators: validators.
* id: Field's ID attribute, which is not written as the attribute name by default.
* default: Default value.
* widget: the specified html control.

Common Field:
* Boolean Field: Boolean Field, rendered as checkbox.
* FileField: File upload Field.

# forms.py
from flask_wtf.file import FileField,FileAllowed,FileRequired
class UploadForm(FlaskForm):
    avatar = FileField(u'Head portrait:',validators=[FileRequired(),FileAllowed([])])

# app.py
@app.route('/profile/',methods=('POST','GET'))
def profile():
    form = ProfileForm()
    if form.validate_on_submit():
        filename = secure_filename(form.avatar.data.filename)
     form.avatar.data.save(os.path.join(app.config['UPLOAD_FOLDER'],filename))
        return u'Upload Success'
    return render_template('profile.html',form=form)
  • FloatField: A Field of floating-point type, but when rendered it is the input of text.
  • IntegerField: Shaped Field. Same as Float Field.
  • RadioField: radio type input. Examples of forms are as follows:
# form.py
class RegistrationForm(FlaskForm):
    gender = wtforms.RadioField(u'Gender:',validators=[DataRequired()])

The template file code is as follows:

<tr>
<td>
{{ form.gender.label }}
</td>
<td>
{% for gender in form.gender %}
{{ gender.label }}
{{ gender }}
{% endfor %}
</td>
</tr>

The code for the app.py file is as follows, adding choices to gender:

@app.route('/register/',methods=['POST','GET'])
def register():
    form = RegistrationForm()
    form.gender.choices = [('1',u'male'),('2',u'female')]
    if form.validate_on_submit():
        return u'success'

    return render_template('register.html',form=form)
  • SelectField: Similar to RadioField. See the following example:
# forms.py
class ProfileForm(FlaskForm):
    language = wtforms.SelectField('Programming Language',choices=[('cpp','C++'),('py','python'),('text','Plain Text')],validators=[DataRequired()])

Look at the app.py file again:

@app.route('/profile/',methods=('POST','GET'))
def profile():
    form = ProfileForm()
    if form.validate_on_submit():
        print form.language.data
        return u'Upload Success'
    return render_template('profile.html',form=form)

The template file is:

<form action="/profile/" method="POST">
{{ form.csrf_token }}
{{ form.language.label }}
{{ form.language() }}
<input type="submit">
</form>
  • StringField: The type rendered into the template is <input type='text'> and is the most basic text validation.
  • PasswordField: Renders a password input tag.
  • TextArea Field: Renders a textarea.

Commonly used validators: data is sent and forms are validated, so validators are needed to validate. Here are some commonly used built-in validators:
* Data Required: Data needs. That is, the value must be uploaded before it can be verified.
* Email: Verify that the uploaded data is mailbox.
* EqualTo: Verify that the uploaded data is equal to another field, usually the password and the confirmation password are equal.
* InputRequired: The raw data needs to be validated. If it's not a special case, you should use InputRequired.
* Length: Length limit, with min and max values.
* NumberRange: Number Range: The interval of a number is limited by min and max, which is satisfied if it is between the two numbers.
* Regexp: Customize regular expressions.
* URLs: Must be in the form of URLs.
* UUID: Verify UUID.

Custom validation fields: Validate_field name (self, field) can be used to validate a field in more detail, as follows:

class ProfileForm(FlaskForm):
    name = wtforms.StringField('name',[validators.InputRequired()])
    def validate_name(self,field):
        if len(field.data) > 5:
            raise wtforms.ValidationError(u'More than 5 characters')

CSRF protection: In flask form, the default is to turn on CSRF protection. If you want to turn off CSRF protection of form, you can pass csrf_enabled=False in to turn off CSRF protection when initializing form. If you want to turn off this default behavior. If you want to add CSRF protection to the request view function without a form, you can turn on the global CSRF protection function:

csrf = CsrfProtect()
csrf.init_app(app)

Or for a view function, use the csrf.protect decorator to turn on the CSRF protection function. And if the global CSRF protection has been activated, if you want to turn off the CSRF protection function of a view function, you can use the csrf.exempt decorator to cancel the protection function of this view function.

CSRF Protection for AJAX: To use CSRF protection in AJAX, you must manually add X-CSRFToken to the Header. But where CSRF comes from, it still needs to be rendered by template, and Flask recommends rendering CSRF in meta tag, as follows:

<meta name="csrf-token" content="{{ csrf_token() }}">

If you want to send an AJAX request, add CSRF before sending, code as follows (using jQuery):

var csrftoken = $('meta[name=csrf-token]').attr('content')
$.ajaxSetup({
    beforeSend: function(xhr, settings) {
        if (!/^(GET|HEAD|OPTIONS|TRACE)$/i.test(settings.type) && !this.crossDomain) {
            xhr.setRequestHeader("X-CSRFToken", csrftoken)
        }
    }
})

Interested in Python and Flask, you can add groups: 482869582 to discuss and learn together.

Topics: Session Attribute Python pip