====== Flask-WTF ====== Doc de **Flask-WTF** et **WTForms** : * [[https://flask-wtf.readthedocs.io]] * [[https://wtforms.readthedocs.io]] YouTube: * [[https://www.youtube.com/watch?v=HvEkVffiNXQ|Des formulaires de pro avec Flask-WTF]] ===== Installation ===== 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 :
{{ form.hidden_tag() }}
{{ form.name.label(class="form-label") }} {{ form.name(class="form-input") }}
{{ form.password.label(class="form-label") }} {{ form.password(class="form-input") }}
{{ form.submit(class="btn btn-primary") }}
===== 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** :-) ) :
...
{{ form.submit(class="w3-button w3-round w3-blue") }} {{ form.cancel(class="w3-button w3-round w3-white w3-border") }}
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)