Outils pour utilisateurs

Outils du site


dev:python:flask:flask_formulaires_wtforms

Différences

Ci-dessous, les différences entre deux révisions de la page.

Lien vers cette vue comparative

Les deux révisions précédentesRévision précédente
Prochaine révision
Révision précédente
dev:python:flask:flask_formulaires_wtforms [2025/02/24 18:35] yoanndev:python:flask:flask_formulaires_wtforms [2026/04/12 10:26] (Version actuelle) yoann
Ligne 1: Ligne 1:
-{{tag>dev python web formulaire}}+{{tag>dev python flask web formulaire}}
  
-:TODO:+:TODO_DOCUPDATE:
  
-====== Python Formulaires WT-Forms ======+====== Flask Créer des formulaires via Flask-WTF ======
  
 +[[https://wtforms.readthedocs.io/en/3.2.x/|WTForms]] est une bibliothèque Python permettant de gérer des formulaires web via des Classes et objets en POO.
 +
 +Ici on utilise le paquet Flask-WTF qui intègre la bibliothèque WTForms au micro framework Flask. 
 +
 +===== Initialiser l'application Flask =====
 +
 +Création d'un dépôt git pour le projet et initialisation de l'application Flask :
 +
 +<code bash>
 +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
 +</code>
 +
 +
 +Peupler le fichier ''helloforms/__init__.py'' :
 +
 +<code python __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 '<h1>Hello World!!!</h1>'
 +
 +
 +
 +if __name__ == '__main__':
 +
 +    # execution en mode debug
 +    app.run(debug=True)
 +
 +</code>
 +
 +
 +Tester l'application via la commande **flask run**:
 +
 +<code bash>
 +FLASK_APP=helloforms FLASK_ENV=development flask run --debug
 +</code>
 +
 +A ce stade la commande doit lancer le serveur web et afficher un message du type :
 +
 +<file>
 +* Serving Flask app 'helloforms'
 + * Debug mode: on
 +WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
 + * Running on http://127.0.0.1:5000
 +Press CTRL+C to quit
 + * Restarting with stat
 + * Debugger is active!
 + * Debugger PIN: 845-679-934
 +</file>
 +
 +Ouvrir son navigateur à l'URL ''http://localhost:5000'' doit afficher le message "Hello World!!!"
 +
 +{{capture-2025-02-27_01.png}}
 +
 +
 +Pour la mise en forme, on utilise le framework Spectre CSS
 +
 +
 +===== Création du formulaire =====
 +
 +  * Pour créer un formulaire, on définit une classe héritant de **FlaskForm**.
 +  * Chaque attribut de la notre classe représentant un champ de formulaire sera un objet héritant de la classe de base ''wtforms.fields.Field'' ;
 +  * L'objet de type formulaire est instancié et traité par le contrôleur (la fonction associée à la route Flask) et transmis à la vue (le template).
 +
 +
 +<code python>
 +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')
 +</code>
 +
 +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.
 +
 +
 +<code python>
 +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")
 +
 +</code>
 +
 +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''.
 +
 +
 +<code python>
 +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()])
 +</code>
 +
 +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''
 +
 +<code python>
 +from flask_wtf import FlaskForm
 +from wtforms import EmailField
 +
 +
 +class RegisterForm(FlaskForm):
 +
 +    email = EmailField(label='Email')
 +</code>
 +
 +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 :
 +
 +<code html _helpers.html>
 +{#
 +Produire le code HTML d'un champ de formulaire.
 +#}
 +
 +{% macro render_field_with_div(field) %}
 +<div>
 +    {{ field.label }} {{ field(**kwargs)|safe }}
 +        {% if field.errors %}
 +            <ul class=errors>
 +            {% for error in field.errors %}
 +                <li>{{ error }}</li>
 +            {% endfor %}
 +            </ul>
 +    {% endif %}
 +</div>
 +{% endmacro %}
 +</code>
 +
 +Une fois la macro définie, on peut l'utiliser dans les différents modèles produisant des formulaires.
 +
 +<code html>
 +<div>
 +    {% from "_helpers.html" import render_field_with_div %}
 +    <form method="POST" action="{{ url_for('frontend.parse_contact_form') }}">
 +        {{ form.csrf_token }}
 +        {{ render_field_with_div(form.first_name) }}
 +        {{ render_field_with_div(form.last_name) }}
 +        {{ render_field_with_div(form.email) }}
 +        {{ render_field_with_div(form.subject) }}
 +        {{ render_field_with_div(form.message) }}
 +        {{ render_field_with_div(form.submit_button) }}
 +    </form>
 +</div>
 +</code>
 +
 +===== Validation =====
 +
 +C'est la fonction contrôleur de la vue qui se charge de valider le formulaire retourné en méthode POST.
 +
 +<code python [highlight_lines_extra="7"] >
 +@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)
 +</code>
 +
 +<note>
 +L'exemple montre bien qu'il n'est pas nécessaire de passer l'objet ''request.form'' à l'instanciation du formulaire ContactForm (héritant de FlaskForm) : il sera automatiquement chargé.
 +</note>
 +
 +La méthode ''validate_on_submit()'' vérifie que la méthode POST est utilisée et que le la saisie est valide.
 +
 +
 +===== Débogages =====
 +
 +==== Échec systématique de la validation ====
 +
 +Lors du traitement du formulaire dans la vue, celui-ci est systématiquement considéré comme invalide.
 +
 +
 +Lorsqu'un formulaire hérite de ''FlaskForm'', il contient systématiquement un **jeton CSRF** (processus de sécurité). Celui-ci doit être rendu dans le template. 
 + 
 +<code html>
 +<form method="POST" action="/">
 +    {{ form.csrf_token }}
 +    
 +    <!-- vos autres champs ici -->
 +     
 +    <input type="submit" value="Go">
 +</form>
 +</code>
  
 ===== Références ===== ===== 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://zephyrnet.com/fr/manipulation-de-formulaires-en-flacon-avec-flacon-wtforms/
   * https://fr.python-3.com/?p=1882   * https://fr.python-3.com/?p=1882
-  * https://youtu.be/HvEkVffiNXQ+  * 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)]] 
 + 
dev/python/flask/flask_formulaires_wtforms.1740422121.txt.gz · Dernière modification : 2025/02/24 18:35 de yoann