1. Livres & vidéos
  2. Django
  3. Formulaires
Extrait - Django Concevez vos applications web professionnelles en Python : du modèle de données au déploiement
Extraits du livre
Django Concevez vos applications web professionnelles en Python : du modèle de données au déploiement Revenir à la page d'achat du livre

Formulaires

Formulaire standard

Pour visualiser le code relatif à ce chapitre : git diff v1.4.6..v1.5.0.

1. Créer un formulaire simple

Lorsque nous parlons de formulaire simple, nous parlons d’un formulaire qui n’est pas lié à un modèle.

Nous souhaitons créer un formulaire capable de générer automatiquement un ensemble de questions et de réponses préremplies selon des règles définies à l’avance.

Voici ce formulaire :

class BulkQuestionAnswerGenerationForm(forms.Form): 
  
    num_questions = forms.IntegerField( 
        label=gettext("Number of questions"), 
        min_value=1, 
        max_value=100, 
    ) 
  
    question_prefix = forms.CharField( 
        label=gettext("Question prefix"), 
        max_length=50, 
    ) 
  
    num_answers_per_question = forms.IntegerField( 
        label=gettext("Number of answers per question"), 
        min_value=1, 
        max_value=10, 
    ) 
  
    answer_prefix = forms.CharField( 
        label=gettext("Answer prefix"), 
        max_length=50, 
    )  

Comme ce formulaire ne repose pas sur un modèle, toutes les contraintes de validation doivent être définies directement dans les champs du formulaire.

Il convient ensuite de décrire chaque champ. Les champs de formulaire présentent de nombreuses similitudes avec les champs de modèle.

Nous verrons dans la section Tunnel de traitement classique comment utiliser ce formulaire.

2. Personnaliser un formulaire pour modèle

Nous avions déjà créé un formulaire pour notre jeu en utilisant ModelForm :

class GameForm(forms.ModelForm): 
  
    class...

Crispy forms

Pour visualiser le code relatif à ce chapitre : git diff v1.10.0..v1.10.1.

1. Pourquoi utiliser crispy ?

Comme nous l’avons vu, les formulaires constituent un outil puissant, géré principalement par du code Python et complété par une courte instruction dans le gabarit :

{{ form.as_p }}  

Cependant, dès que l’on souhaite intégrer un formulaire à une bibliothèque graphique, il faut consacrer beaucoup de temps au template afin de gérer toutes les parties du formulaire et d’ajouter aux endroits appropriés les classes CSS et les identifiants nécessaires.

Voici un exemple (non présent dans le dépôt) :

<form method="POST"> 
    {% csrf_token %} 
    <div class="form-group"> 
        <label for="{{ form.num_questions.id_for_label }}">Number 
of questions</label> 
        {{ form.num_questions }} 
    </div> 
    <div class="form-group"> 
        <label for="{{ form.question_prefix.id_for_label 
}}">Question prefix</label> 
        {{ form.question_prefix }} 
    </div> 
    <div class="form-group"> 
        <label for="{{ form.num_answers_per_question.id_for_label 
}}">Number of anwser per question</label> 
        {{ form.num_answers_per_question }} 
    </div> 
    <div class="form-group"> 
        <label for="{{ form.answer_prefix.id_for_label }}">Answer 
prefix</label> 
        {{ form.answer_prefix }} 
    </div> 
    <button type="submit"...

Crispy Formsets

Pour visualiser le code relatif à ce chapitre : git diff v1.10.1..v1.10.2.

1. Préparation

Nous allons créer les interfaces permettant de jouer une partie, c’est-à-dire de répondre à un quiz. Pour cela, nous devons créer l’objet Play et nous appuyer sur l’objet Entry. Ce dernier constitue une simple table d’association entre un jeu, une question et une réponse, mais il joue un rôle fondamental dans la construction simple de nos formulaires et sous-formulaires.

Nous allons faire cela dans une vue destinée à créer la partie :

def create_play(request, pk: int): 
    try: 
        player = request.user.player 
    except AttributeError: 
        messages.add_message( 
            request, 
            messages.WARNING, 
            gettext("Please authenticate to play") 
        ) 
        url = reverse_lazy("login") 
    except User.player.RelatedObjectDoesNotExist: 
        messages.add_message( 
            request, 
            messages.ERROR, 
            gettext("You do not have a player profile") 
        ) 
        url = reverse_lazy("game:list") 
    else: 
        play = Play.objects.create(player=player, game_id=pk) 
        Entry.objects.bulk_create( 
            [ 
                Entry(play=play, question=question) 
                for...

Création de la vue

Maintenant que le formulaire est terminé, voici la vue :

class PlayUpdateView(UpdateView): 
    model = Play 
    template_name = "app/play_form.html" 
    form_class = PlayForm 
    success_url = reverse_lazy("game:list") 
  
    def get_object(self, queryset=None): 
        return get_object_or_404(Play, pk=self.kwargs['pk']) 
  
    def get_context_data(self, **kwargs): 
        context = super().get_context_data(**kwargs) 
        if self.request.method == "POST": 
            context["entry_set"] = PlayFormSet(self.request.POST, 
instance=self.object) 
        else: 
            context["entry_set"] = PlayFormSet(instance=self.object) 
        return context 
  
    def form_valid(self, form): 
        context = self.get_context_data() 
        entry_set = context["entry_set"] 
        with transaction.atomic(): 
            if entry_set.is_valid(): 
                entry_set.save() 
                messages.add_message(self.request, messages.SUCCESS, gettext("Saved.")) 
            else: ...