Évolutions du système de formulaire avec Django 5.0 !

5 décembre 2023
Aymeric

La dernière version majeure de Django, la version 5, vient tout juste de sortir. Elle apporte son lot de nouveautés, dont certaines sont très attendues particulièrement par ma propre personne 😁 !

Nous allons voir ici les nouveautés liées au système de rendu des formulaires.

Le système de rendu des formulaires Django avait déjà beaucoup évolué dans les versions précédentes de manière très positive.

Avant la version 4.0

Avant la version 4.0 de Django, lorsque nous voulions mettre en place un système de rendu personnalisé pour nos formulaires, la documentation nous conseillait de créer un fichier html, et d'inclure celui-ci dans notre template.

# forms.py
class MyForm(forms.Form):
    ...
<!-- Notre fichier my_custom_form.html -->
{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}
# views.py
def index(request):
    form = MyForm()
    return render(request, "index.html", {"form": form})
<!-- Le template de notre views -->
<form method="post">{% csrf_token %}
    {% include "my_custom_form.html" form=my_form %}
    <input type="submit" value="Submit" />
</form>

Ce que je trouvais dérangeant avec cette méthode, c'est que le système de rendu du formulaire est détaché du formulaire.

A partir de la version 4.0

A partir de la version 4.0 de Django

A partir de la version 4.0 de Django, le système de formulaire nous permet de définir le template à utiliser pour le rendu du formulaire. Cela permet de garder coupler le rendu du formulaire avec celui-ci.

# Notre formulaire, ou l'on définit le template à utiliser
class MyForm(forms.Form):
    template_name = 'my_custom_form.html'
<!-- Notre fichier my_custom_form.html -->
{% for field in form %}
    <div class="fieldWrapper">
        {{ field.errors }}
        {{ field.label_tag }} {{ field }}
    </div>
{% endfor %}
# views.py
def index(request):
    form = MyForm()
    return render(request, "index.html", {"form": form})
<!-- Le template de notre views -->
<form method="post">{% csrf_token %}
    {{ form }}
    <input type="submit" value="Submit" />
</form>

On voit ici la différence entre les deux méthodes, avant nous devions utiliser la balise {% include %} pour inclure le rendu du formulaire, et maintenant il nous suffit d'utiliser {{ form }} pour afficher le formulaire.

Ce que j'aime bien avec ce système, c'est de considérer le formulaire comme un composant , à part entière. De cette manière, la view n'a pas à ce soucier du rendu du formulaire.

Si l'on souhaite utiliser le même formulaire sur plusieurs pages avec des rendus légèrement différents, il suffit de créer le nouveau template et de définir un nouveau formulaire qui hérite du premier.

# forms.py
class MyForm(forms.Form):
    template_name = 'my_custom_form.html'

class MyOtherForm(MyForm):
    template_name = 'my_other_form.html'

A partir de la version 4.2 de Django

Par ailleurs à partir de la version 4.2 , il est possible de définir le template à utiliser de manière globale pour tous les formulaires de notre projet en définissant un "Renderer".

# settings.py
from django.forms.renderers import TemplatesSetting


class CustomFormRenderer(TemplatesSetting):
    form_template_name = "form_snippet.html"


FORM_RENDERER = "project.settings.CustomFormRenderer"

Je n'ai pas encore eu trop l'occasion de tester cette fonctionnalité, mais j'imagine que cela nous permet encore plus de flexibilité dans le rendu de nos formulaires.

A partir de la version 5.0

A partir de la version 5.0 de Django, le système de rendu des formulaires évolue encore et nous propose deux nouvelles fonctionnalités.

Nouvelle méthode render()

Tout d'abord, il est maintenant possible de définir le template à utiliser directement depuis notre view depuis laquelle on utilise le formulaire.

# forms.py

class MyForm(forms.Form):
    template_name = 'my_custom_form.html'

# views.py
def index(request):
    form = MyForm()
    rendered_form = form.render("another_custom_form.html")
    return render(request, "index.html", {"form": rendered_form})

On voit ici que notre formulaire MyForm utilise le template my_custom_form.html par défaut, mais que l'on peut aussi surcharger ce template depuis notre view en utilisant la méthode render() .

L'avantage ici est que l'on est pas obligé d'utiliser l'héritage comme dans un exemple précédent pour utiliser un template différent. On peut le faire directement depuis la view.

Template pour les champs du formulaire

La deuxième nouveauté est que l'on peut aussi définir des templates pour les champs du formulaire ! C'est probablement l'une des fonctionnalités qui manquait le plus à Django.

Tous l'intérêt de cette fonctionnalité est de ne plus avoir à définir le template du formulaire en entier, d'utiliser celui par défaut de Django ( django/forms/div.html ), et de définir le template des champs que l'on souhaite personnaliser.

# forms.py
class MyForm(forms.Form):
    subject = forms.CharField(template_name="my_custom_field_template.html")
<!-- my_custom_field_template.html -->
<label for="{{ field.id_for_label }}">{{ field.label }}</label>
{% if field.help_text %}
    <div class="helptext">{{ field.help_text|safe }}</div>
{% endif %}
{{ field }}
{{ field.errors }}

Dans cet exemple, le formulaire utilise le template par défaut de Django, mais le champ subject utilise le template my_custom_field_template.html .

Le lien vers la documentation de Django pour cette fonctionnalité : documentation .

Conclusion

Cette nouvelle version de Django nous apporte encore une fois des fonctionnalités qui vons nous permettre d'avoir plus de flexibilité dans nos développements.

Articles récents

Catégories

Tags