J'adore l'open-source, et j'adore le libre.
Aujourd'hui, à 20h30, je me dis que j'aimerais bien pouvoir utiliser les nouveaux form input de HTML5 dans mes formulaires django. Je me rappelle alors de l'excellent django-floppyforms de ce cher Bruno Renié.
django-floppy-forms : la librairie de widgets
Quelques minutes et un pip install django-floppyforms plus tard, je me retrouve avec un petit formulaire de test :
#!/usr/bin/env python # -*- coding: utf-8 -*- import floppyforms as forms class TestForm(forms.Form): name = forms.CharField() email = forms.EmailField(widget=forms.EmailInput(attrs={'placeholder': 'john@example.com'})) url = forms.URLField()
Ce qui me donne le résultat visuel suivant :
On y voit bien le placeholder dans le champ de type email. Sur l'image suivante, on voit la validation faite directement au niveau du browser (firefox 4b11) :
A 20h45 : "ce que j'aimerais vraiment bien, c'est pouvoir scinder mon formulaire en fieldsets, comme le permet l'administration de django". Va-t-il falloir que je me mette à développer? Que nenni, cher lecteur, comme tu l'aura deviné, un autre développeur de talent, un certain Carl Meyer nous propose le très pratique django-form-utils.
django-form-utils : une méthode propre pour spécifier des fieldsets
Encore quelques minutes et un pip install django-form-utils plus tard, voici le code du formulaire :
#!/usr/bin/env python # -*- coding: utf-8 -*- import floppyforms as forms from form_utils.forms import BetterForm class TestForm(BetterForm): name = forms.CharField() email = forms.EmailField(widget=forms.EmailInput( attrs={'placeholder': 'john@example.com'})) url = forms.URLField() class Meta: fieldsets = [ ('test', { 'fields': ['name', 'email'], 'legend': 'a test legend', }), ('other test', { 'fields': ['url'], 'description': 'a test description', 'classes': ['advanced', 'collapse'] }), ] row_attrs = {'name': {'style': 'background: #f00'}}
Et le template, un poil plus complexe que le {{ form.as_p }} précédent :
{% if form.non_field_errors %}{{ form.non_field_errors }}{% endif %} {% for fieldset in form.fieldsets %} <fieldset class="{{ fieldset.classes }}"> {% if fieldset.legend %}<legend>{{ fieldset.legend }}</legend>{% endif %} {% if fieldset.description %} <p class="description">{{ fieldset.description }}</p> {% endif %} {% for field in fieldset %} {% if field.is_hidden %} {{ field }} {% else %} <p{{ field.row_attrs }}> {{ field.errors }} {{ field.label_tag }} {{ field }} </p> {% endif %} {% endfor %} </fieldset> {% endfor %}
Et voici le résultat (les moqueurs reconnaîtrons mon talent pour tout ce qui touche au design) :
21h00 : Tout ça est vraiment super. Mais... quitte a être exigeant, est-ce que je pourrai avoir des fieldsets ET un template plus simple? Par exemple un layout générique du style uni-form... c'est là que Daniel Greenfeld entre en jeu avec son projet pour djangonautes fainéants django-uni-form.
django-uni-form: les uni-forms pour django
Vous connaissez le refrain, quelques minutes et un pip install django-uni-form plus tard :
#!/usr/bin/env python # -*- coding: utf-8 -*- import floppyforms as forms from django.forms import Form from uni_form.helpers import FormHelper, Submit from uni_form.helpers import Layout, Fieldset class TestForm(Form): name = forms.CharField() email = forms.EmailField(widget=forms.EmailInput( attrs={'placeholder': 'john@example.com'})) url = forms.URLField() helper = FormHelper() layout = Layout(Fieldset('a test legend', 'name', 'email'), Fieldset('other test', 'url')) helper.add_layout(layout) submit = Submit('submit','test this form') helper.add_input(submit)
Et le template, beaucoup plus simple du coup :
{% load uni_form_tags %} {% with form.helper as helper %} {% uni_form form helper %} {% endwith %}
Conclusion
Il fait bon être fainéant, utiliser django, et les outils déjà disponibles en open-source. Les applications que j'ai présentées ici ont été bien pensées, et sont pluggable : on peut facilement les rajouter à son projet et les utiliser ou même les combiner!
Dans notre cas on a pu tester l'utilisation de widgets html5 (django-floppy-forms) avec un layout par fieldset défini dans la class Meta du formulaire (django-form-utils), ou grâce à un helper (django-uni-form).
Pour le moment mon cœur balance entre les deux, la solution utilisant la sous-class Meta me paraissant plus naturelle, mais l'utilisation d'un layout robuste et soigné comme les uni-form étant plus simple, "standard" et économisant plus de temps.
A quand un projet permettant d'hériter d'une classe UniForm, dans laquelle on définit les fieldsets dans une sous-classe Meta ?
Ah, au fait, de 21h00 à 23h00, écriture de ce billet... une demi heure pour tester trois projets, et presque deux heures pour en parler, personne n'aurait une pluggable app qui pond des billets ?