Doc de Flask-WTF et WTForms :
YouTube:
pip install flask-wtf
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 |
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 action="" method="post"> {{ form.hidden_tag() }} <div class="form-group"> {{ form.name.label(class="form-label") }} {{ form.name(class="form-input") }} </div> <div class="form-group"> {{ form.password.label(class="form-label") }} {{ form.password(class="form-input") }} </div> {{ form.submit(class="btn btn-primary") }} </form>
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")
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) :
<form action="" method="post" novalidate> ... </form>
Afficher les messages d'erreur de chaque champ :
<div class="form-group"> {{ form.email.label(class="form-label") }} {{ form.email(class="form-input" }} {% for error in form.email.errors %} {{ error }} {% endfor %} </div> <div class="form-group"> {{ form.password.label(class="form-label") }} {{ form.password(class="form-input" }} {% for error in form.password.errors %} {{ error }} {% endfor %} </div>
Classe formulaire :
... class MyEditForm(FlaskForm): ... submit = SubmitField("Valider") cancel = SubmitField("Annuler")
Rendu dans le template (avec classes pour w3css ) :
<form action="" method="post" class="..."> ... <div class="w3-section"> {{ form.submit(class="w3-button w3-round w3-blue") }} {{ form.cancel(class="w3-button w3-round w3-white w3-border") }} </div> </form>
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" ...
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)