简体   繁体   中英

Flask and WTForms with custom validation

I am creating an online form with Python, to send an online form. The form consists of a mixture of free input fields, and standard options. What it does now is convert the input to a mail, and send it. That's great, but I would like to build in a functionality that checks the input first. I need the length of two different inputfields to be of the size. So if someone enters 4 products and only 3 quantities, I want it to return a warning that these amounts differ.

base.py:

from flask import *
from wtforms import *
import yagmail

yag = yagmail.SMTP('email', 'pass')

# App config.
DEBUG = True

app = Flask(__name__)
app.config.from_object(__name__)
app.config['SECRET_KEY'] = 'key'


class ReusableForm(Form):
    naam = TextField('Name:', validators=[validators.required()])

@app.route("/", methods=['GET', 'POST'])

def index():
    form = ReusableForm(request.form)

    print form.errors
    if request.method == 'POST':
        # Process all input
        naam=request.form['naam']
        productcodes=request.form['productcodes']
        productquantity=request.form['productquantity']

        # Convert SKU & EAN input to list of entries
        productcodes = [int(i) for i in productcodes.strip('{}').split('\n')]
        productquantity = [int(i) for i in productquantity.strip('{}').split('\n')]

        # tried this; didn't work
        # if len(productcodes) != len(productquantity):
        # flash('Unequal inputs') 

        if form.validate():
            # Comment when form is validates
            flash('Order succesvol: ' + naam)

            (send mail)

        else:
            flash('Error: All the form fields are required. ')

    return render_template('hello.html', form=form)

if __name__ == "__main__":
    app.run()

hello.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
    <head>
        <title>Form</title>
       <link rel="stylesheet" media="screen" href ="static/css/bootstrap.min.css">
       <link rel="stylesheet" href="static/css/bootstrap-theme.min.css">
       <meta name="viewport" content = "width=device-width, initial-scale=1.0">
    </head>
    <body>


<div class="container">


  <h2>Form</h2>
  <form  action="" method="post" role="form">
    {{ form.csrf }}
    <div class="form-group">
      <label for="naam">Naam:</label>
      <select name="naam" class="selectpicker form-control">
        <option value="Jack">Jack</option>
        <option value="John">John</option>
      </select>
      <br>


      <label for="productcodes">SKU-codes:</label>
      <textarea class="form-control" id="productcodes" name="productcodes"></textarea>
       <br>
       <textarea class="form-control" id="productquantity" name="productquantity"></textarea>
      <br>

    </div>
    <button type="submit" class="btn btn-success">Send</button>
  </form>

  <br>
        {% with messages = get_flashed_messages(with_categories=true) %}
            {% if messages %}

        {% for message in messages %}
            {% if "Error" not in message[1]: %}
                <div class="alert alert-info">
                <strong>Success! </strong> {{ message[1] }}
                </div>
            {% endif %}

            {% if "Error" in message[1]: %}
                <div class="alert alert-warning">
                {{ message[1] }}
                </div>
            {% endif %}
        {% endfor %}
            {% endif %}
        {% endwith %}

</div>
<br>
</div>
</div>
</body>
</html>

So what i would like to have is that upon the first click, the check is executed. If the size of the input of productcodes is smaller than the size of productquantity, the user has to edit the inputs. If not, the user has to confirm and is able to send the mail.

The lines that are commented out in base.py didn't work.

Thanks in advance!

Quick and Dirty

Based on the commented-out code, in your original attempt there was nothing stopping the form from validating and submitting. Your if len(productcodes) != len(productquantity) just flashed a message, which only shows on the next page load, but doesn't stop validation of the form. form.validate() can only validate the fields you tell it about.

Change the check to be something like:

if len(productcodes) != len(productquantity) and form.validate():

That way your basic check will bounce to the failed validation code path.

The "Right" Way

Keep in mind, even if that works, you're still basing your check on parsing text from a <textarea> , with little to enforce the format. Any unexpected input is likely to break it.

I'd strongly recommend you rethink your form to be a bit more in line with how WTForms and Flask work. Each form field should map directly to an attribute of your Form subclass. That way you can use the built-in validators, and not have to create your own. You should probably look at using something other than a raw <textarea> as well. It may be a bit more work up-front, but it will make it a lot easier for you and your users down the road.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM