gwift-book/source/django/forms.adoc

4.9 KiB
Raw Blame History

Forms

Ou comment valider proprement des données entrantes.

Note
intégrer le dessin XKCD avec Little Bobby Table sur lassainissement des données en entrée :-p

Quand on parle de forms, on ne parle pas uniquement de formulaires Web. On pourrait considérer quil sagit de leur objectif principal, mais on peut également voir un peu plus loin: on peut en fait voir les forms comme le point dentrée pour chaque donnée arrivant dans notre application: il sagit en quelque sorte dun ensemble de règles complémentaires à celles déjà présentes au niveau du modèle.

Lexemple le plus simple est un fichier .csv: la lecture de ce fichier pourrait se faire de manière très simple, en récupérant les valeurs de chaque colonne et en lintroduisant dans une instance du modèle.

Mauvaise idée.

Les données fournies par un utilisateur doivent toujours être validées avant introduction dans la base de données. Notre base de données étant accessible ici par lORM, la solution consiste à introduire une couche supplémentaire de validation.

Le flux à suivre est le suivant:

  1. Création dune instance grâce à un dictionnaire

  2. Validation des données et des informations reçues

  3. Traitement, si la validation a réussi.

Ils jouent également plusieurs rôles:

  1. Validation des données, en plus de celles déjà définies au niveau du modèle

  2. Contrôle sur le rendu à appliquer aux champs

Ils agissent come une glue entre lutilisateur et la modélisation de vos structures de données.

Dépendance avec le modèle

Un form peut dépendre dune autre classe Django. Pour cela, il suffit de fixer lattribut model au niveau de la class Meta dans la définition.

from django import forms

from wish.models import Wishlist

class WishlistCreateForm(forms.ModelForm):
    class Meta:
        model = Wishlist
        fields = ('name', 'description')

De cette manière, notre form dépendra automatiquement des champs déjà déclarés dans la classe Wishlist. Cela suit le principe de DRY <dont repeat yourself>`_, et évite quune modification ne pourrisse le code: en testant les deux champs présent dans lattribut `fields, nous pourrons nous assurer de faire évoluer le formulaire en fonction du modèle sur lequel il se base.

Rendu et affichage

Le formulaire permet également de contrôler le rendu qui sera appliqué lors de la génération de la page. Si les champs dépendent du modèle sur lequel se base le formulaire, ces widgets doivent être initialisés dans lattribut Meta. Sinon, ils peuvent lêtre directement au niveau du champ.

from django import forms
from datetime import date
from .models import Accident

class AccidentForm(forms.ModelForm):
    class Meta:
        model = Accident
        fields = ('gymnast', 'educative', 'date', 'information')
        widgets = {
            'date' : forms.TextInput(
                     attrs={
                        'class' : 'form-control',
                        'data-provide' : 'datepicker',
                        'data-date-format' : 'dd/mm/yyyy',
                        'placeholder' : date.today().strftime("%d/%m/%Y")
                     }),
            'information' : forms.Textarea(
                            attrs={
                                'class' : 'form-control',
                                'placeholder' : 'Context (why, where, ...)'
                            })

Squelette par défaut

On a dun côté le {{ form.as_p }} ou {{ form.as_table }}, mais il y a beaucoup mieux que ça ;-) Voir les templates de Vitor.

Crispy-forms

Comme on la vu à linstant, les forms, en Django, cest le bien. Cela permet de valider des données reçues en entrée et dafficher (très) facilement des formulaires à compléter par lutilisateur.

Par contre, cest lourd. Dès quon souhaite peaufiner un peu laffichage, contrôler parfaitement ce que lutilisateur doit remplir, modifier les types de contrôleurs, les placer au pixel près, …​ Tout ça demande énormément de temps. Et cest là quintervient `Django-Crispy-Forms <http://django-crispy-forms.readthedocs.io/en/latest/>`_. Cette librairie intègre plusieurs frameworks CSS (Bootstrap, Foundation et uni-form) et permet de contrôler entièrement le layout et la présentation.

(c/c depuis le lien ci-dessous)

Pour chaque champ, crispy-forms va :

  • utiliser le verbose_name comme label.

  • vérifier les paramètres blank et null pour savoir si le champ est obligatoire.

  • utiliser le type de champ pour définir le type de la balise <input>.

  • récupérer les valeurs du paramètre choices (si présent) pour la balise <select>.

Validation des données

Note
parler ici des méthodes clean.

En conclusion

  1. Toute donnée entrée par lutilisateur doit passer par une instance de form.

  2. euh ?