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: ...