pip install flask-wtf
===== Création du formulaire =====
from flask_wtf import FlaskForm
from wtforms import StringField
class RegisterForm(FlaskForm):
name = StringField('Nom', validators=[])
password = PasswordField('Mot de passe', validators=[])
submit = SubmitField("S'inscrire")
Types de champs :
^ StringField | Champ texte ||
^ EmailField | ||
^ PasswordField | ||
^ TextAreaField | ||
^ FloatField | (préférer **DecimalField**) ||
^ DateField | Date avec calendrier ||
^ TimeField | Heure ||
^ DecimalField | Champ numérique décimal | ''places=X'' |
^ BooleanField | ||
^ SelectField | Liste dropdown | ''choices=[ ('valeur', 'texte'), ('valeur2', 'texte2') ]'' |
^ SubmitField | ||
===== Utilisation du formulaire =====
from flask import Flask, render_template, redirect, url_for
from forms import RegisterForm;
app = Flask(__name__)
@app.route('/register', methods=['get', 'post'])
def register():
form = RegisterForm()
# Si le formulaire a été validé
if form.validate_on_submit():
# Afficher les nouvelles valeurs des champs
print('Nom: ' + form.name.data)
print('Mot de passe: ' + form.password.data)
# Insert dans la DB
# Flash message
# Rediriger vers une autre page
return redirect(url_for('index'))
# Sinon, initialiser les valeurs des champs
form.name.data = 'Dupont'
form.password.data = ''
# Afficher le formulaire
return render_template('register.html', form=form)
Intégration dans le template :
===== Ajout d'ID aux champs =====
Par défaut c'est le nom du champ, mais si on désire imposer un **id**
on peut le passer au constructeur des champs :
class MyForm(FlaskForm):
nom = StringField("Nom", id="edtNom")
sexe = SelectField("Sexe", id="cmbSexe")
===== Validation =====
Ajout de contraintes de validation aux champs :
from flask_wtf import FlaskForm
from wtforms import StringField
from wtforms.validators import DataRequired, Email, Length, ValidationError
class RegisterForm(FlaskForm):
email = StringField('Nom', validators=[DataRequired(), Email()])
password = PasswordField('Mot de passe', validators=[DataRequired(), Length(min=4, max=12)])
submit = SubmitField("S'inscrire")
# validation custom
def validate_email(self, email):
if email.data == "root@domain.com":
raise ValidationError("Cet email est déjà enregistré")
Désactiver la validation par défaut du navigateur (ajouter **novalidate**) :
Afficher les messages d'erreur de chaque champ :
{{ form.email.label(class="form-label") }}
{{ form.email(class="form-input" }}
{% for error in form.email.errors %}
{{ error }}
{% endfor %}
{{ form.password.label(class="form-label") }}
{{ form.password(class="form-input" }}
{% for error in form.password.errors %}
{{ error }}
{% endfor %}
===== Boutons Valider et Annuler =====
Classe formulaire :
...
class MyEditForm(FlaskForm):
...
submit = SubmitField("Valider")
cancel = SubmitField("Annuler")
Rendu dans le template (avec classes pour **w3css** :-) ) :
Traitement du formulaire dans le contrôleur :
form = MyEditForm()
...
if form.validate_on_submit():
# Selon qu'on a validé ou annulé, les champs
# "submit" et "cancel" valent True ou False
# Donc on peut faire ceci :
if form.submit.data:
# On a cliqué sur le bouton "Valider"
...
if form.cancel.data:
# On a cliqué sur le bouton "Annuler"
...
===== Remplir un SelectField =====
Source: [[https://stackoverflow.com/questions/63209897/flask-wtforms-building-a-selectfield-from-a-table]]
**EXEMPLE À TESTER :**
from flask_wtf import FlaskForm
from wtforms import SelectField
from app.models import Categories
class MyForm(FlaskForm):
# ...
category = SelectField("Catégorie")
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.category.choices = Categories.query.all()
**Remplissage via Javascript => désactiver la validation**
Si la liste de choix est remplie via Javascript une fois le formulaire déjà créé,
la validation échouera car la valeur sélectionnée ne fera jamais partie des choix
possibles. Pour résoudre ce problème, il faut désactiver la validation pour ce
champ :
class MyForm(FlaskForm):
# ...
category = SelectField("Catégorie", validate_choice=False)