git init hello-wtf
cd hello-wtf/
git branch -m main
# Création de l'environnement et installation des packages
python3 -m venv venv
source venv/bin/activate
pip install Flask Flask-WTF email_validator
# Création de l'application Flask
mkdir -p helloforms/{static,templates}
touch helloforms/__init__.py
chmod a+x helloforms/__init__.py
Peupler le fichier ''helloforms/__init__.py'' :
#!/usr/bin/env python
from flask import Flask
app = Flask(__name__)
@app.route('/')
def show_home_page():
"""Build and return home page
"""
return 'Hello World!!!
'
if __name__ == '__main__':
# execution en mode debug
app.run(debug=True)
Tester l'application via la commande **flask run**:
FLASK_APP=helloforms FLASK_ENV=development flask run --debug
A ce stade la commande doit lancer le serveur web et afficher un message du type :
from flask_wtf import FlaskForm
from wtforms import EmailField, SubmitField
from wtforms.fields.simple import BooleanField
class NewsLetterForm(FlaskForm):
email = EmailField(label='Email')
news_letter = BooleanField(label="S'abonner à la news letter")
submit_button = SubmitField(label='Valider')
Comme illustré ci-dessus, le constructeur des objets héritant de la classe de base ''wtforms.fields.Field'' accepte notamment les paramètres :
* ''label'' : le label associé au champ ;
* ''default'' : valeur par défaut du champ, peut être un ''callable'' (un nom de fonction exécutable) ;
* ''description'' : une description associée au champ, utilisée généralement par les help text ;
* ''filters'' : tableau, séquence de ''callable'' exécutés pour traiter les données du champ ;
* ''validators'' : tableau de validators appelés lors de l'exécution de ''validate''.
La liste exhaustive des paramètres est disponible dans la documentation [[https://wtforms.readthedocs.io/en/3.2.x/fields/#basic-fields]]
Quelques objets représentant les champs de base des formulaires :
* **StringField** : Champ type texte ;
* **TextAreaField** :
* **SelectField** :
* **BooleanField** : Champ de type checkbox ;
* **PasswordField** : Champ de saisie de mot de passe
* **HiddenField** : Champ masqué ;
* **SubmitField** : Bouton soumission du formulaire ;
Champs plus spécifiques :
* **EmailField** ;
* **TelField** ;
* **URLField** ;
* **TimeField** ;
* **ColorField** ;
* **IntegerField** : Saisie d'un nombre entier;
* **IntegerRangeField**
* **FloatField**
* **DecimalRangeField** ;
* **FileField**
===== Les filtres =====
Les filtres (filters) permettent de traiter, en amont de la validation, les valeurs saisies par l'utilisateur. On les utilise couramment pour :
* Retirer les espaces en début et fin de saisie ;
* Passer la saisie en majuscule, en minuscule ;
* Arrondir les valeurs décimales etc.
from flask_wtf import FlaskForm
from wtforms import StringField
class RegisterForm(FlaskForm):
lastname = StringField(label='Nom', default="DOE",
filters=[str.strip, str.upper],
description="Champ de saisie de votre nom")
Ci-dessus, on utilise les filtres pour retirer les espaces autour de la saisie et la passer en majuscules.
===== Les validateurs =====
Les **validators** permettent de contrôler la saisie de l'utilisateur. On les importe depuis ''wtforms.validators''.
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import InputRequired, Email
class RegisterForm(FlaskForm):
email = StringField(label='Email', validators=[InputRequired(),Email()])
Ici on instancie deux validators pour contraindre la saisie de l'utilisateur :
* Le champs ne doit pas être vide,
* La saisie doit respecter le formalisme d'un email.
Dans ce cas, peut également utiliser la classe ''EmailField'' :
from flask_wtf import FlaskForm
from wtforms import EmailField
class RegisterForm(FlaskForm):
email = EmailField(label='Email')
Il existe de nombreux validators citons par exemple **InputRequired**, **Length**, **Email**, **URL**, **NumberRange**, **IPAddress**, **MacAddress**, **Regexp**, etc. Il est possible de définir ses propres validators.
* Ici la [[https://wtforms.readthedocs.io/en/3.2.x/validators/|documentation exhaustive des validators WTForms]]
===== Rendu du formulaire dans le template =====
Du côté du template, on peut s'appuyer sur des macros Jinja2 pour factoriser le code en charge de produire le HTML du formulaire :
{#
Produire le code HTML d'un champ de formulaire.
#}
{% macro render_field_with_div(field) %}
{{ field.label }} {{ field(**kwargs)|safe }}
{% if field.errors %}
{% for error in field.errors %}
- {{ error }}
{% endfor %}
{% endif %}
{% endmacro %}
Une fois la macro définie, on peut l'utiliser dans les différents modèles produisant des formulaires.
{% from "_helpers.html" import render_field_with_div %}
===== Validation =====
C'est la fonction contrôleur de la vue qui se charge de valider le formulaire retourné en méthode POST.
@frontend_bp.post('/contact')
def parse_contact_form():
"""
Analyse le formulaire de contact renseigné par l'utilisateur.
"""
from app.services.forms import ContactForm
form = ContactForm()
if form.validate_on_submit():
# Les valeurs saisies sont correctes
return redirect(url_for('frontend.supply_home'))
else:
# Reafficher le formulaire pour permettre à l'utilisateur de corriger
flash('Vérifier les valeurs saisies')
return render_template('contact.html', form=form)
===== Références =====
* [[https://flask-wtf.readthedocs.io/en/1.2.x/|Documentation Flask-WTF]]
* [[https://flask.palletsprojects.com/en/stable/patterns/wtforms/| Documentation Flask : validation des formulaires WTF (palletsprojects.com) (en)]]
* [[https://wtforms.readthedocs.io/en/3.2.x/|Documentation Officielle WTForms]]
* [[https://spectre-org.github.io/spectre-docs/docs/get-started/|Documentation Framework CSS Spectre]]
* https://zephyrnet.com/fr/manipulation-de-formulaires-en-flacon-avec-flacon-wtforms/
* https://fr.python-3.com/?p=1882
* Vidéo [[https://youtu.be/HvEkVffiNXQ| Créer des formulaires avec Flask-WTF]]
* https://picturepan2.github.io/spectre/getting-started.html
* https://spectre-org.github.io/spectre-docs/docs/layout/
* [[https://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-iii-web-forms| Les formulaires dans Flask (miguelgrinberg.com)]]