OUJOOD.COM
Comment fonctionne la validation dans Django
Quand vous appelez is_valid() sur un formulaire soumis, Django déclenche une chaîne de validation en plusieurs étapes :
- Validation du type de chaque champ — un
IntegerFieldrejette les lettres. - Validation des contraintes du champ —
max_length,min_value,required. - Exécution des validators déclarés sur le champ.
- Exécution de la méthode
clean_nomchamp()si elle existe. - Exécution de la méthode
clean()pour la validation croisée.
Si une étape échoue, Django enregistre l'erreur dans form.errors et is_valid() retourne False.
Validation par champ avec clean_nomchamp()
Pour ajouter une règle de validation spécifique à un champ, définissez une méthode nommée clean_ suivi du nom du champ. Django l'appelle automatiquement après la validation de base.
from django import forms
from .models import Membres
class MembreForm(forms.Form):
prenom = forms.CharField(max_length=255)
nom = forms.CharField(max_length=255)
mail = forms.EmailField()
def clean_mail(self):
mail = self.cleaned_data['mail']
# Vérifier que l'email n'est pas déjà utilisé
if Membres.objects.filter(mail=mail).exists():
raise forms.ValidationError("Cette adresse email est déjà enregistrée.")
return mail # Toujours retourner la valeur nettoyée
def clean_prenom(self):
prenom = self.cleaned_data['prenom']
# Interdire les prénoms trop courts
if len(prenom) < 2:
raise forms.ValidationError("Le prénom doit contenir au moins 2 caractères.")
# Normaliser la casse
return prenom.capitalize()
Deux règles à retenir : si la validation réussit, retournez toujours la valeur (éventuellement transformée). Si elle échoue, levez forms.ValidationError avec le message à afficher.
Validation croisée avec clean()
Certaines règles portent sur plusieurs champs à la fois — un mot de passe doit correspondre à sa confirmation, une date de fin doit être après une date de début. La méthode clean() s'exécute après tous les clean_champ() et reçoit l'ensemble des données nettoyées.
class InscriptionForm(forms.Form):
prenom = forms.CharField(max_length=255)
mail = forms.EmailField()
mot_de_passe = forms.CharField(widget=forms.PasswordInput)
confirmation_mdp = forms.CharField(widget=forms.PasswordInput,
label='Confirmer le mot de passe')
def clean(self):
# super().clean() retourne les données nettoyées de tous les champs
donnees = super().clean()
mdp = donnees.get('mot_de_passe')
confirm = donnees.get('confirmation_mdp')
if mdp and confirm and mdp != confirm:
# add_error attache l'erreur à un champ spécifique
self.add_error('confirmation_mdp', "Les mots de passe ne correspondent pas.")
return donnees
Validators réutilisables
Un validator est une fonction (ou un objet callable) qui reçoit une valeur et lève ValidationError si elle est invalide. L'avantage : il peut être réutilisé sur plusieurs champs ou plusieurs formulaires.
from django.core.exceptions import ValidationError
def valider_pas_de_chiffres(valeur):
# Refuse les valeurs contenant des chiffres
if any(c.isdigit() for c in valeur):
raise ValidationError("Ce champ ne doit pas contenir de chiffres.")
class MembreForm(forms.Form):
# Le validator est déclaré dans la liste validators= du champ
prenom = forms.CharField(max_length=255,
validators=[valider_pas_de_chiffres])
nom = forms.CharField(max_length=255,
validators=[valider_pas_de_chiffres])
Validators intégrés de Django
Django fournit plusieurs validators prêts à l'emploi dans django.core.validators :
from django.core.validators import RegexValidator, MinLengthValidator
class MembreForm(forms.Form):
# Numéro de téléphone français
telephone = forms.CharField(
validators=[RegexValidator(
regex=r'^0[1-9][0-9]{8}$',
message="Numéro de téléphone invalide (format : 0612345678)"
)]
)
# Mot de passe d'au moins 8 caractères
mot_de_passe = forms.CharField(
widget=forms.PasswordInput,
validators=[MinLengthValidator(8)]
)
Afficher les erreurs dans le template
Quand is_valid() retourne False, Django re-rend le formulaire avec les erreurs. Elles s'affichent automatiquement avec {{ form.as_p }}, mais vous pouvez les contrôler finement :
<form method="post">
{% csrf_token %}
{% if form.errors %}
<div class="erreurs">
<!-- Erreurs globales (non liées à un champ) -->
{{ form.non_field_errors }}
</div>
{% endif %}
<div>
{{ form.prenom.label_tag }}
{{ form.prenom }}
<!-- Erreurs spécifiques au champ prenom -->
{% if form.prenom.errors %}
<p class="erreur">{{ form.prenom.errors.0 }}</p>
{% endif %}
</div>
<div>
{{ form.mail.label_tag }}
{{ form.mail }}
{% if form.mail.errors %}
<p class="erreur">{{ form.mail.errors.0 }}</p>
{% endif %}
</div>
<button type="submit">Enregistrer</button>
</form>
form.non_field_errors affiche les erreurs générées dans clean() qui ne sont pas attachées à un champ précis. form.champ.errors.0 affiche le premier message d'erreur du champ.
Par carabde | Mis à jour le 05 mai 2025