Flask-WTF
=========



Cette extension permet de gérer simplement des formulaires.
```python
pip install flask
pip install Flask-WTF
```
Nous allons contruire une application possédant un formulaire de contact avec 4 champs:
- nom
- mail
- sujet
- message
Tout les champs sont obligatoires et nous validerons le format du mail
Notre application aura l'arborescence suivante
```
dir
|__ myapp.py
|__ myapp.cfg
|__ templates
| |__ contact.html
| |__ home.html
| |__ layout.html
|__ statics
|__ css
|__ main.css
```
contact.html
```html
{% extends "layout.html" %}
{% block content %}
```note```
on utilise içi les templates avec des notions d'extends
myapp.cfg
```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import logging
DEBUG = True
PATH_STATICS = './statics'
SECRET_KEY = 'secret_key'
PORT = 5001
HOST = '0.0.0.0'
MAIL_SERVER = 'srvpzex1'
```
myapp.py
```python
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os
import logging
from flask import Flask
import flask
from flask_wtf import Form
from wtforms import TextField, TextAreaField, SubmitField, validators
app = Flask(__name__)
app.config.from_pyfile('myapp.cfg')
```
class RegistrationForm(Form):
username = TextField('Username', [validators.Length(min=4, max=25)])
email = TextField('Email Address', [validators.Length(min=6, max=35)])
name = TextField("Name", [validators.Required("Please enter your name.")])
subject = TextField("Subject", [validators.Required("Please enter a subject.")])
message = TextAreaField("Message", [validators.Required("Please enter a message.")])
datefield = DateField('datefield')
datetimefield = DateTimeField('datetimefield')
decimalfield = DecimalField('decimalfield')
filefield = FileField('filefield')
floatfield = FloatField('floatfield')
integerfield = IntegerField('integerfield')
radiofield = RadioField('radiofield', choices=[('cpp', 'C++'), ('py', 'Python'), ('text', 'Plain Text')])
selectfield = SelectField('selectfield', choices=[('cpp', 'C++'), ('py', 'Python'), ('text', 'Plain Text')])
password = PasswordField('New Password', [
validators.Required(),
validators.EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [validators.Required()])
submit = SubmitField("Send")
@app.route('/home')
def home():
app.logger.debug(flask.render_template('home.html'))
return flask.render_template('home.html')
@app.route('/contact', methods=['GET', 'POST'])
def contact():
form = ContactForm()
if flask.request.method == 'POST':
if form.validate() == False:
app.logger.error('All fields are required.')
flask.flash('All fields are required.')
return flask.render_template('contact.html', form=form)
else:
app.logger.debug("name : %s" % form.name.data)
app.logger.debug("email : %s" % form.email.data)
app.logger.debug("subject : %s" % form.subject.data)
app.logger.debug("message : %s" % form.message.data)
return 'Form posted.'
elif flask.request.method == 'GET':
return flask.render_template('contact.html', form=form)
@app.route("/")
def static_web(path):
app.logger.debug('load static %s' % path)
return flask.send_from_directory(app.config['PATH_STATICS'],path)
if __name__ == "__main__":
handler = logging.StreamHandler()
handler.setLevel(app.config['LEVEL'])
app.logger.addHandler(handler)
app.run(host = app.config['HOST'],
port = app.config['PORT'])
On peut tester sur http://127.0.0.1:5001/contact
Il est important de noter que nous gérons les erreurs champs par champs au niveau du contact.html
mais aussi au niveau gloabl grâce à la fonction flash.
On peut aussi facilement rajouter un form de gestion du login
```python```
from wtforms import TextField, TextAreaField, SubmitField, validators, PasswordField, BooleanField
class RegistrationForm(Form):
username = TextField('Username', [validators.Length(min=4, max=25)])
email = TextField('Email Address', [validators.Length(min=6, max=35)])
password = PasswordField('New Password', [
validators.Required(),
validators.EqualTo('confirm', message='Passwords must match')
])
confirm = PasswordField('Repeat Password')
accept_tos = BooleanField('I accept the TOS', [validators.Required()])
@app.route('/register', methods=['GET', 'POST'])
def register():
form = RegistrationForm(flask.request.form)
if flask.request.method == 'POST' and form.validate():
flash('Thanks for registering')
return redirect(url_for('login'))
return flask.render_template('register.html', form=form)
Et pour register.html afin de simplifier son écriture on peut créer une fonction de template
register.html
```html```
{% from "_formhelpers.html" import render_field %}
{% extends "layout.html" %}
{% block content %}
{% endblock %}
_formhelpers.html
```html```
{% macro render_field(field) %}
{{ field.label }}
{{ field(**kwargs)|safe }}
{% if field.errors %}
{% for error in field.errors %}
{{ error }}
{% endfor %}
{% endif %}
{% endmacro %}
Concernant les éléments qu'on peut uiliser via le module wtform il y a une excellente doc https://wtforms.readthedocs.org/en/latest
Il existe plusieurs validateurs:
- validators.DataRequired(message=None)
- validators.Email(message=None)
- validators.EqualTo(fieldname, message=None)
- validators.InputRequired(message=None)
- validators.IPAddress(ipv4=True, ipv6=False, message=None)
- validators.Length(min=-1, max=-1, message=None)
- validators.MacAddress(message=None)
- validators.NumberRange(min=None, max=None, message=None)
- validators.Optional(strip_whitespace=True)
- validators.Regexp(regex, flags=0, message=None)
- validators.URL(require_tld=True, message=None)
- validators.UUID(message=None)
- validators.AnyOf(values, message=None, values_formatter=None)
- validators.NoneOf(values, message=None, values_formatter=None)
Il est possible de créer facilement des nouveaux validateurs
```python```
def my_length_check(form, field):
if len(field.data) > 50:
raise ValidationError('Field must be less than 50 characters')
class MyForm(Form):
name = StringField('Name', [InputRequired(), my_length_check])