• 12 heures
  • Moyenne

Ce cours est visible gratuitement en ligne.

course.header.alt.is_video

course.header.alt.is_certifying

J'ai tout compris !

Mis à jour le 09/03/2022

Incluez plusieurs formulaires sur une page

Connectez-vous ou inscrivez-vous gratuitement pour bénéficier de toutes les fonctionnalités de ce cours !

Maintenant que nous avons vu comment créer plusieurs instances de modèles en envoyant un seul formulaire, voyons comment inclure différents formulaires, par le biais d’envois séparés, sur la même page.

Pour démontrer ceci, nous allons construire une page depuis laquelle nous modifierons et supprimerons un billet de blog.

Étape 1 : Créez les formulaires

Pour supprimer l’instance de  Blog  , créez un nouveau formulaire,  DeleteBlogForm  . Pour modifier l’instance de  Blog  , utilisez le  BlogForm  déjà créé.

Néanmoins, il nous faut un moyen de distinguer ces deux formulaires lorsque nous récupérons les données de la requête  POST  dans la vue.

Pour atteindre ce but, attachez un champ caché à chaque formulaire. Voici comment faire :

# blog/forms.py
class BlogForm(forms.ModelForm):
edit_blog = forms.BooleanField(widget=forms.HiddenInput, initial=True)
class Meta:
model = models.Blog
fields = ['title', 'content']
class DeleteBlogForm(forms.Form):
delete_blog = forms.BooleanField(widget=forms.HiddenInput, initial=True)

Vous avez attaché un champ   edit_blog  et un champ   delete_blog  aux formulaires   BlogForm  et   DeleteBlogForm , respectivement. Ces champs utilisent le widget   HiddenInput   , et ne seront pas vus par l’utilisateur sur le front-end. Le choix du type de champ et de la valeur initiale est quelque peu arbitraire, vu que nous allons simplement vérifier la présence du champ dans la vue.

Étape 2 : Incluez les formulaires dans une vue

Maintenant que nous avons les formulaires, gérons-les dans une vue.

Premièrement, créez une vue  edit_blog  sans gestion de requête  POST  .

# blog/views.py
@login_required
def edit_blog(request, blog_id):
blog = get_object_or_404(models.Blog, id=blog_id)
edit_form = forms.BlogForm(instance=blog)
delete_form = forms.DeleteBlogForm()
if request.method == 'POST':
pass
context = {
'edit_form': edit_form,
'delete_form': delete_form,
}
return render(request, 'blog/edit_blog.html', context=context)

Depuis que vous avez ajouté les champs cachés aux formulaires, vous pouvez vérifier quel formulaire est envoyé en vérifiant la présence de ce champ dans les données  POST  . Puis, vous pouvez simplement gérer le formulaire comme d’habitude.

@login_required
def edit_blog(request, blog_id):
blog = get_object_or_404(models.Blog, id=blog_id)
edit_form = forms.BlogForm(instance=blog)
delete_form = forms.DeleteBlogForm()
if request.method == 'POST':
if 'edit_blog' in request.POST:
edit_form = forms.BlogForm(request.POST, instance=blog)
if edit_form.is_valid():
edit_form.save()
return redirect('home')
if 'delete_blog' in request.POST:
delete_form = forms.DeleteBlogForm(request.POST)
if delete_form.is_valid():
blog.delete()
return redirect('home')
context = {
'edit_form': edit_form,
'delete_form': delete_form,
}
return render(request, 'blog/edit_blog.html', context=context)

Étape 3 : Ajoutez le gabarit

Maintenant que la vue est construite, travaillons sur le gabarit :

# blog/templates/blog/edit_blog.html
{% extends 'base.html' %}
{% block content %}
<h2>Modifier le billet</h2>
<form method="post">
{{ edit_form.as_p }}
{% csrf_token %}
<button type="submit" >Sauvegarder</button>
</form>
<hr>
<h3>Supprimer le billet ?</h3>
<form method="post">
{{ delete_form }}
{% csrf_token %}
<button type="submit" >Supprimer</button>
</form>
{% endblock content %}

L’inclusion des champs cachés garantit que chaque formulaire n’est géré que lorsque vous avez l’intention de l’envoyer. Vous pouvez désormais inclure n’importe quelle quantité de formulaires sur la même page.

Étape 4 : Ajoutez le modèle d’URL

Ajoutez maintenant le modèle d’URL pour la page de modification du billet.

# fotoblog/urls.py
urlpatterns = [
path('blog/<int:blog_id>/edit', blog.views.edit_blog, name='edit_blog'),
]

Étape 5 : Ajoutez un lien vers la page de modification du billet

Et pour finir, ajoutez un lien vers la page de modification du billet depuis la page de visualisation du billet.

# blog/templates/blog/view_blog.html
{% extends 'base.html' %}
{% block content %}
<h2>{{ blog.title }}</h2>
<p><a href="{% url 'edit_blog' blog.id %}">Modifier le billet</a></p>
<img src="{{ blog.photo.image.url }}">
<p>{{ blog.photo.caption }}</p>
<p>{{ blog.content }}</p>
{% endblock content %}

Et voilà, nous avons fini ! Voyons à quoi ressemble la page de modification du billet :

Elle a l’air très bien ! Vous avez remarqué les deux boutons « Sauvegarder » et « Supprimer » séparés sur la page ? Ces deux boutons vont envoyer nos deux formulaires différents. Amusez-vous à tester cette fonctionnalité !

Incluez plusieurs instances du même formulaire avec des ensembles de formulaires, ou formsets

Vous possédez maintenant deux techniques pour inclure différents formulaires sur la même page. Vous pouvez les envoyer simultanément ou séparément. Mais que se passerait-il si vous vouliez inclure le même formulaire plusieurs fois sur une même page ?

Vous pouvez utiliser des ensembles de formulaires, ou formsets. Découvrez dans la vidéo ci-dessous comment créer une page qui permettra à un utilisateur de charger plusieurs photos en même temps.

Étape 1 : Créez un formset dans une vue avec  formset_factory 

Vous avez déjà  PhotoForm  qui peut instancier le modèle  Photo  . Vous pouvez réutiliser ce formulaire plutôt que d’en créer un nouveau.

Pour générer un formset avec ce formulaire, utilisez la méthodeformset_factoryque vous trouverez dans   django.forms. Cette méthode prend la classe formulaire (« form ») comme premier argument, puis un autre argument,extra, qui définit combien d’instances du formulaire vous voulez faire générer. Cette fonction « factory » (usine) renvoie une  classe, que vous devrez ensuite instancier dans la vue.

Concrètement, voici de quoi ça a l’air :

# blog/views.py
from django.forms import formset_factory
@login_required
def create_multiple_photos(request):
PhotoFormSet = formset_factory(forms.PhotoForm, extra=5)
formset = PhotoFormSet()
if request.method == 'POST':
pass
return render(request, 'blog/create_multiple_photos.html', {'formset': formset})

Pour traiter les données  POST , vous pouvez exécuter la méthode  is_valid()   sur le  formset  , exactement comme vous pouvez le faire sur un formulaire. Puis, vous pouvez itérer à travers les formulaires dans le  formset  en utilisant une boucle. Vous pouvez les gérer comme vous le feriez habituellement. Leformset  ne sera pas invalidé si des formulaires individuels sont vides, alors vérifions si un formulaire contient des données avant de le sauvegarder, comme ceci :

# blog/views.py
@login_required
def create_multiple_photos(request):
PhotoFormSet = formset_factory(forms.PhotoForm, extra=5)
formset = PhotoFormSet()
if request.method == 'POST':
formset = PhotoFormSet(request.POST, request.FILES)
if formset.is_valid():
for form in formset:
if form.cleaned_data:
photo = form.save(commit=False)
photo.uploader = request.user
photo.save()
return redirect('home')
return render(request, 'blog/create_multiple_photos.html', {'formset': formset})

Ceci sauvegardera tous les formulaires, avant de nous rediriger vers la page d’accueil. Et maintenant, ajoutons un gabarit.

Étape 2 : Créez le gabarit

Il y a deux méthodes pour inclure un formset dans un gabarit. La plus simple : inclure le  formset  comme vous le feriez pour un formulaire.

# blog/templates/blog/create_multiple_photos.html
{% extends 'base.html' %}
{% block content %}
<h2>Télécharger plusieurs photos</h2>
<form method="post" enctype="multipart/form-data">
{{ formset.as_p }}
{% csrf_token %}
<button type="submit" >Publier</button>
</form>
{% endblock content %}

Vous voudrez peut-être présenter chaque formulaire du formset individuellement. Pour ce faire, n’oubliez pas d’inclure  {{ formset.management_form }}  dans les balises  <form>. Le  management_form   n’inclut rien qui sera vu par l’utilisateur sur le front-end, mais il comprend certaines métadonnées dont Django a besoin pour traiter le formset, par exemple le nombre de formulaires dans le formset.

Pour inclure un formset dans une page tout en gérant l’affichage de chaque formulaire, vous pouvez ajouter :

# blog/templates/blog/create_multiple_photos.html
{% extends 'base.html' %}
{% block content %}
<h2>Télécharger des photos</h2>
<form method="post" enctype="multipart/form-data">
{{ formset.management_form }}
{% csrf_token %}
{% for form in formset %}
{{ form.as_p }}
{% endfor %}
<button type="submit" >Publier</button>
</form>
{% endblock content %}

Étape 3 : Ajoutez le modèle d’URL

À nouveau, vous devez ajouter le modèle d’URL.

# fotoblog/urls.py
urlpatterns = [
path('photo/upload-multiple/', blog.views.create_multiple_photos,
name='create_multiple_photos'),
]

Étape 4 : Ajoutez un lien dans la barre latérale

Et un lien dans la barre latérale.

# templates/base.html
...
<p><a href="{% url 'photo_upload' %}">Télécharger une photo</a></p>
<p><a href="{% url 'create_multiple_photos' %}">Télécharger plusieurs photos</a></p>
<p><a href="{% url 'upload_profile_photo' %}">Changer la photo de profil</a></p>
...

Et c’est tout ! Vous pouvez maintenant inclure plusieurs instances du même formulaire sur la même page. Voyons de quoi ça a l’air :

Capture d'écran d'une page formset
Capture d'écran d'une page formset

Testez cette possibilité, avant de me retrouver au prochain chapitre. Nous y verrons comment surcharger des méthodes de modèle.

En résumé 

  • Vous pouvez gérer plusieurs formulaires séparés sur une seule page, en incluant un champ caché qui identifie le formulaire envoyé.

  • Vous pouvez utiliser des ensembles de formulaires, dits formsets, pour créer plusieurs instances différentes du même formulaire sur une seule page.

Maintenant que vous savez gérer plusieurs formulaires dans une seule vue, vous pouvez apprendre à étendre des modèles avec des méthodes personnalisées !

Exemple de certificat de réussite
Exemple de certificat de réussite