Home > database >  Dynamically Add or Remove WTForms validators in Flask
Dynamically Add or Remove WTForms validators in Flask

Time:06-14

Is there a way to do this?

Below is an example of what I'm trying to do:

class TestForm(FlaskForm):
  email = EmailField('Email', validators=[InputRequired('Email is required.')])
  start = SubmitField()

Then in a route:

del form.email.validators
# I also tried:
form.email.validators.remove

Basically I want to use stored data to determine if the field should be required or not for a predefined form.

CodePudding user response:

Dynamically create an internal subclasses of the form within your view. Remove any validators from the fields of the internal subclass and then instance a form from the internal subclass. In code, something like:

Define a form, the first_name field has two validators.

class TestForm(FlaskForm):
    first_name = StringField(validators=[InputRequired(), Length(8)])
    submit = SubmitField()

In your view:

# Dynamic subclass
class F(TestForm):
    pass

# Remove the length validator.
# Validators are in a dict called kwargs
validators = F.first_name.kwargs.get('validators')
for validator in validators:
    if isinstance(validator, Length):
        validators.remove(validator)

# instance a form
_form = F()
# use the form ....

Single file example app.py:

from flask import Flask, render_template_string
from flask_wtf import FlaskForm
from wtforms import StringField, SubmitField
from wtforms.validators import InputRequired, Length

app = Flask(__name__)
app.config['SECRET_KEY'] = '13332311ecd738748f27a992b6189d3f5f30852345a1d5261e3e9d5a96722fb9'


class TestForm(FlaskForm):
    first_name = StringField(validators=[InputRequired(), Length(8)])
    submit = SubmitField()


html_template = '''
    {% if form.first_name.errors %}
        <ul >
        {% for error in form.first_name.errors %}
            <li>{{ error }}</li>
        {% endfor %}
        </ul>
    {% endif %}
    <form role="form" method="post" action="" name="Form1">
        {{ form.hidden_tag() }}
        {{ form.first_name }}
        {{ form.submit() }}
    </form>      
'''

success_template = '''
    <h1>Success</h1>      
'''


@app.route('/', methods=['GET', 'POST'])
def index():

    # Dynamic subclass
    class F(TestForm):
        pass

    # Remove the length validator.
    # Validators are in a dict called kwargs
    validators = F.first_name.kwargs.get('validators')
    for validator in validators:
        if isinstance(validator, Length):
            validators.remove(validator)

    # instance a form
    _form = F()
    # print the validators
    for field in _form:
        print(f"Field: {field.name} has {len(field.validators)} validator(s)")
        for validator in field.validators:
            print(validator)

    if _form.validate_on_submit():
        print('Validation passed')
        return render_template_string(success_template)

    return render_template_string(html_template, form=_form)


if __name__ == '__main__':
    app.run()
  • Related