Table des matières

Formulaires

Méthode avec `ModelForm`

documentation

Création d'un fichier forms.py dans le dossier de l'application, et ajout d'une class qui hérite de ModelForm

cette classe pourrait aussi être créée dans le fichier `models.py` mais par convention, on met le code des formulaires dans le fichier `forms.py`

from django import forms
from .models import Article

#...

class ArticleForm(forms.ModelForm):
    class Meta:
        model = Article
        fields = ['title', 'content', 'is_draft', 'categories']
        labels = { 'title': 'Titre' }
        help_texts = { 'title': 'Veuillez saisir un titre' } 

La plupart du temps, les formulaires correspondent étroitement avec les modèles Django. Les champs étant déjà définis au niveau du modèle, il est inutile de les redéfinir pour créer le formulaire.

fields permet de choisir les champs que l'on veut afficher dans le formulaire.

labels et help_texts permettent de surcharger les labels et d'ajouter un texte d'aide si besoin.

Affichage du formulaire dans le gabarit

Exemple de fichier add_article.html

<form action="" method="post">
  {% csrf_token %}
  {{ form }}
  <input type="submit" value="Submit">
</form>

La balise form permet d'afficher le formulaire qui est passé au gabarit. Cela va créer automatiquement les balises label et input.

form peut prendre trois options afin de configurer l'affichage que l'on souhaite :

{% csrf_token %} permet de protéger le formulaire contre la faille CSRF (Cross-Site Request Forgery). Voir cet article pour davantage d'informations.

Il est également possible d'afficher manuellement les champs, voir la documentation Affichage manuel des champs

La vue

Les données de formulaire renvoyés sont traitées par une vue (views.py), en principe la même qui a servi à produire le formulaire. Cela permet de réutiliser une partie de la même logique.

On utilise request.method pour savoir si la requête a été faire en GET ou en POST

from django.shortcuts import render, redirect
from .models import Article
from .forms import ArticleForm

#...

def add_article(request):
    # Si requête POST, le formulaire a été soumis
    if request.method == 'POST':
        form = ArticleForm(request.POST)

        # Validation des données
        if form.is_valid():
            form.save()
            # Redirige vers une page de confirmation par exemple
            return redirect('confirm-article')
            
    # Si requête, on crée un formulaire vierge
    else:
        form = ArticleForm()

    return render(request, 'blogue/add_article.html', {'form': form})


def confirm_article(request):
    return render(request, 'blogue/confirm_article.html')

Vous devez créer un fichier confirm_article.html avec un message de confirmation par exemple…

Si form.is_valid() est False, l'objet form est renvoyé au gabarit avec les erreurs afin de les afficher automatiquement.

Route

Pour finir, il faut définir les routes correspondantes dans le fichier urls.py

from django.urls import path
from . import views

urlpatterns = [
  #...
  path('add-article/', views.add_article, name='addArticle'),
  path('confirm-article/', views.confirm_article, name='confirm-article')
]


Autre méthode sans ModelForm mais avec Form

documentation

Reprenons le fichier forms.py.

from django import forms
#...
class CategoryForm(forms.Form):
    title = forms.CharField(max_length=255, label = "Titre")
    description = forms.CharField(widget=forms.Textarea, help_text = "Saisir une description")

Documentation des types de champs.

En utilisant Form à la place de ModelForm, on doit saisir chaque champ de formulaire.

La vue

Dans views.py, il faut enregistrer l'objet grâce à la méthode objects.create.

Avant d'enregistrer, il faut utiliser la méthode .cleaned_data afin de “nettoyer” les données. Django va par exemple convertir les types pour les enregistrer correctement dans la base de données.

def add_category(request):
    if request.method == 'POST':
        form = CategoryForm(request.POST)
        if form.is_valid():
            title = form.cleaned_data['title']
            description = form.cleaned_data['description']
            Category.objects.create(title=title, description=description)
            return redirect('confirm-category')
    # Si requète GET, on crée un formulaire vierge
    else:
        form = CategoryForm()

    return render(request, 'blogue/add_category.html', {'form': form})

Validation

En plus de la validation automatique, on peut ajouter nos propres validations dans forms.py

Exemple :

class CategoryForm(forms.Form):
    title = forms.CharField(max_length=255, label = "Titre")
    description = forms.CharField(widget=forms.Textarea, help_text = "Saisir une description")
    num = forms.DecimalField(max_digits=10, decimal_places=2)

    def clean_num(self):
        data = self.cleaned_data['num']
        if data < 0:
            raise forms.ValidationError("Veuillez saisir un nombre > 0")
        return data

    def clean_title(self):
        data = self.cleaned_data['title']
        if data == "chat":
            raise forms.ValidationError("Il y a déjà trop de chats sur Internet !")
        return data