How to use Flask WTF form

  • 2021-07-16 02:40:26
  • OfStack

flask_wtf is a form verification module of flask framework, which can easily generate forms, and can also be used as a verification tool for json data interaction, supporting hot plug.

Installation


pip install Flask-WTF

Flask-WTF is actually a package of wtforms components, so that it supports the hot swap of flask framework.

Simple use


# app.py
from flask import Flask, current_app, request, render_template
from forms import MyForm

app = Flask(__name__,template_folder='static/html')
@app.route('/',methods=['GET','POST'])
def login():
  form = MyForm()
  if form.validate_on_submit():
    return 'OK'
  return render_template('forms/index.html', form=form)
if __name__ == '__main__':
  app.run(host='127.0.0.1', port=80, debug=True)

# forms.py
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired

class MyForm(FlaskForm):
  name = StringField('name', validators=[DataRequired()])

# forms/index.html
<form method="POST" action="/">
{{ form.csrf_token }}
{{ form.name.label }} {{ form.name(size=20) }}
<input type="submit" value="Go">
</form>

flask_wtf Definition Field

flask_wtf completely uses the field model of wtforms component, and wtforms defines fields in fields module; It is divided into core and simple. core module defines commonly used fields, and simple expands one field on the basis of core module, which will be automatically verified at the field level.

Field type


# core.py
__all__ = (
  'BooleanField', 'DecimalField', 'DateField', 'DateTimeField', 'FieldList',
  'FloatField', 'FormField', 'IntegerField', 'RadioField', 'SelectField',
  'SelectMultipleField', 'StringField',
)

Description of Common Fields:

BooleanField: Boolean types, such as Flask, True StringField: String type DecimalField: Decimal point text field, such as: '1.23' DateField: Date field in format: '% Y-% m-% d' DateTimeField: Date field in format: '% Y-% m-% d% H:% M:% S' FieldList: A list of all 1 field types, such as: FieldList (StringField ('Name', [validators. required ()]) FloatField: Floating point number type IntegerField: Plastic SelectMultipleField: Multiple check boxes RadioField: Radio Box

simple.py

TextAreaField: Text field that accepts multiple lines of input PasswordField: Password field, which will not be displayed directly in clear text in the browser FileField: Upload files, but do not process validation files, requiring manual processing HiddenField: Hidden Fields SubmitField: Button TextField: Alias of string type, discarded

Form definition


#  Parameters: 
class UserAdminForm(FlaskForm):
  username = StringField(label=' User name ', validators=[DataRequired(),Length(4,20)])
  password_hash = PasswordField(label=' Password ',validators=[DataRequired(),Length(4,20)])
  limit = SelectField(label=' User rights ',
            choices=[('guest', ' All permissions '),
                 ('operation', ' Readable, writable and not deleted '),
                 ('management', ' Readable and not writable ')],
            default='guest') #  Authority 

#  Field 1 General parameter 
# label: The name of the field 
# default : Default 
# validators Validation sequence for a field 
# description Description of the field 
# choices : SelectField And its subclass has fields, selection box, multiple selection 1

Validation sequence of field

Field parameter validators can specify the validation sequence for submitting the form, in order from left to right. The default optional validation is in the wtforms. validators module. The encapsulated validation methods are:


__all__ = (
  'DataRequired', 'data_required', 'Email', 'email', 'EqualTo', 'equal_to',
  'IPAddress', 'ip_address', 'InputRequired', 'input_required', 'Length',
  'length', 'NumberRange', 'number_range', 'Optional', 'optional',
  'Required', 'required', 'Regexp', 'regexp', 'URL', 'url', 'AnyOf',
  'any_of', 'NoneOf', 'none_of', 'MacAddress', 'mac_address', 'UUID'
)

In the module, case corresponds to case, for example, DataRequired corresponds to data_required.

DataRequired/data_required: Verify that the data is real, that is, it cannot be empty and must be a non-blank string, otherwise an StopValidation error is triggered. InputRequired/input_required: The difference between DataRequired and DataRequired is that it can be a blank string; Required/required: Alias for data_required Email/email: Verification conforms to the format of the message, only the most basic verification; EqualTo/equal_to: Compare the values of two fields, such as password and confirmation password. If they are not equal, an error will be triggered. equal_to (field, message), you need to enter the name of another field. IPAddress/ip_address: Verify that it is an ip address, and validate the IPV4 address by default. MacAddress/mac_address: Verify compliance with mac format; UUID: Whether it is in uuid format; URL/url: Verify compliance with url format; Regexp/regexp: Validate the field with the supplied regular expression; Regexp (r "") Length/length: Sets the length of the field value, Length (min, max); NumberRange/number_range: Set the value range of 1 number field, which can be for floating-point numbers and decimals; NumberRange (min, max) Optional/optional: Allow fields to be empty and stop validation; NoneOf/none_of: Comparing the incoming data with the invalid is to throw an exception; Noneof (values). Anyof/any_of: Compares the incoming data to the default data, not an exception. Anyof (values).

Custom field validation

If the default validation sequence does not meet our requirements, we can customize the fields through inheritance.


from wtforms.validators import DataRequired,Length,StopValidation
class NewStringField(StringField):
  """
   Customize 1 New fields 
  """
  def pre_validate(self, form):
    """ Validation method, in the validators Before validating the sequence """
    x:str = form.name.data
    if not x.startswith('g'):
      raise StopValidation("your data must be startswith 'g'")

  def post_validate(self, form, validation_stopped):
    """
     Validation method, in the validators After the validation sequence 
    :param form: The form object to which the field belongs 
    :param validation_stopped: The results of the previous validation sequence, True Indicates that the verification is passed, False Indicates authentication failure 
    :return:
    """
    if not validation_stopped:
      raise ValueError(" Verification failed! ")
    pass

Triggering an StopValidation exception stops the authentication chain;

Custom form validation

Generally speaking, if there is additional validation required for the form, 1 customize the additional validation method of the form instead of recustomizing the new fields, which form already provides us with.

Look at the source code of Form object:


def validate(self):
  """
  Validates the form by calling `validate` on each field, passing any
  extra `Form.validate_<fieldname>` validators to the field validator.
  """
  extra = {}
  for name in self._fields:
    inline = getattr(self.__class__, 'validate_%s' % name, None)
    if inline is not None:
      extra[name] = [inline]

  return super(Form, self).validate(extra)

When the Form object calls the validate function, it automatically looks for the method of validate_% s to add to the validation sequence, and executes after the validation sequence of the original field has been validated.


class MyForm(FlaskForm):
  name = StringField('name', validators=[DataRequired(), Length(4,20)])
  def validate_name(self, field):
    print(field.data)
    if hasattr(self, 'name') and len(self.name.data) > 5:
      print(self.name.data)
      return True
    raise ValidationError(' Exceed 5 Characters ')

#  In a custom validation method, throwing an exception uses the ValidationError , validate Will automatically capture. 

Form object

flask_wtf recommends replacing it with FlaskForm, a subclass of the Form object that provides all the properties and methods required by the form. So how does the Form object automatically implement the form function?

Analysis of FlaskForm object source code:


class FlaskForm(Form):
  class Meta(DefaultMeta):
    def wrap_formdata(self, form, formdata):
      pass

  def __init__(self, formdata=_Auto, **kwargs):
    csrf_enabled = kwargs.pop('csrf_enabled', None)
    pass
  def is_submitted(self):
    pass
  def validate_on_submit(self):
    pass
  def hidden_tag(self, *fields):
    pass
  def validate(self):
    pass

Meta class is defined inside FlaskForm, which adds some methods protected by csrf, so when creating a form, you must import FlaskForm instead of Form. is_submitted: Check for 1 active request request; validate_on_submit: Calls the is_submitted and validate methods and returns a Boolean value to determine whether the form is submitted; validate: Field-level validation. Each field has one validate method. Calling validate from FlaskForm will call validate method validation for all fields. If all validation passes, Ture will be returned, otherwise an exception will be thrown. hidden_tag: Gets the fields hidden by the form; wrap_formdata: Gets form in request, which is executed each time the form object is initialized to get form from request.

Important attribute

form. data: A dictionary of field names and values; form. errors: The information dictionary for validation failures is valid only after the validate_on_submit method is called; form. name. data: The value of the field name; form. name. type: Type of field name

Common Scenarios

Login authentication


# froms.py
class UserPasswordForm(FlaskForm):
  """
   Log in to the submitted form 
  """
  username = StringField('User', validators=[DataRequired()])
  password = PasswordField('Password', validators=[DataRequired()])

# form.html
<form method="POST" action="/">
{{ form.csrf_token }}
{{ form.username.label }} {{ form.username(size=20) }}
{{ form.password.label }} {{ form.password }}
<input type="submit" value="Go">
</form>

# views.py
@app.route('/login',methods=['GET','POST'])
def login():
  form = UserPasswordForm()
  if form.validate_on_submit():
    #  Validation form 
    if form.username.data == "xiaoming" and form.password.data == '123':
      return 'OK'
  return render_template('forms/index.html', form=form)

ajax Request Conversion Form

Sometimes we don't have the form of html page, only the data interaction requested by ajax, but we want to borrow Form to define the interface and verify the received data. If the request method of ajax is one of ('POST', 'PUT', 'PATCH', 'DELETE'), FlaskForm will automatically call request. form and request.get_json () methods from request objects to receive data, so this method is 10 points convenient. Note: The get method is no longer one of them.


# app.py
from flask import Flask, current_app, request, render_template
from forms import MyForm

app = Flask(__name__,template_folder='static/html')
@app.route('/',methods=['GET','POST'])
def login():
  form = MyForm()
  if form.validate_on_submit():
    return 'OK'
  return render_template('forms/index.html', form=form)
if __name__ == '__main__':
  app.run(host='127.0.0.1', port=80, debug=True)

# forms.py
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired

class MyForm(FlaskForm):
  name = StringField('name', validators=[DataRequired()])

# forms/index.html
<form method="POST" action="/">
{{ form.csrf_token }}
{{ form.name.label }} {{ form.name(size=20) }}
<input type="submit" value="Go">
</form>

0

form Enable csrf Protection

The default csrf protection is turned on, and the SECRET_KEY parameter must be set for app whenever {{form. csrf_token}} is added to the html file.


# app.py
from flask import Flask, current_app, request, render_template
from forms import MyForm

app = Flask(__name__,template_folder='static/html')
@app.route('/',methods=['GET','POST'])
def login():
  form = MyForm()
  if form.validate_on_submit():
    return 'OK'
  return render_template('forms/index.html', form=form)
if __name__ == '__main__':
  app.run(host='127.0.0.1', port=80, debug=True)

# forms.py
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired

class MyForm(FlaskForm):
  name = StringField('name', validators=[DataRequired()])

# forms/index.html
<form method="POST" action="/">
{{ form.csrf_token }}
{{ form.name.label }} {{ form.name(size=20) }}
<input type="submit" value="Go">
</form>

1

1 generic data csrf protection

Similarly, the SECRET_KEY parameter must be set.


# app.py
from flask import Flask, current_app, request, render_template
from forms import MyForm

app = Flask(__name__,template_folder='static/html')
@app.route('/',methods=['GET','POST'])
def login():
  form = MyForm()
  if form.validate_on_submit():
    return 'OK'
  return render_template('forms/index.html', form=form)
if __name__ == '__main__':
  app.run(host='127.0.0.1', port=80, debug=True)

# forms.py
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired

class MyForm(FlaskForm):
  name = StringField('name', validators=[DataRequired()])

# forms/index.html
<form method="POST" action="/">
{{ form.csrf_token }}
{{ form.name.label }} {{ form.name(size=20) }}
<input type="submit" value="Go">
</form>

2

Related articles: