Les formulaires sont une partie vitale de nombreux sites. Dans ce tutoriel, on va créer un générateur de formulaire avec de nombreux champs différents, avec lequel vous pouvez créer des formulaires sur n'importe quelle page Wagtail.
Il existe plusieurs façons d'ajouter des formulaires à votre site Wagtail. Wagtail a son propre générateur de formulaires intégré, ce qui est idéal pour les formulaires à la volée dans de nombreuses situations. Cependant, dans un site multilingue avec wagtailtrans (comme on l'a mis en place précédemment), toutes les pages sont sous-classées à partir de TranslatablePage
, tandis que la page de formulaire Wagtail n'est pas sous-classée à partir du modèle Page
mais à partir de AbstractForm
. Cela rend impossible ou du moins pas trivial d'utiliser le générateur de formulaires intégré de Wagtail pour les sites multilingues. Le codage en dur des formulaires dans des modèles de page, comme on l'a fait précédemment avec un formulaire de commentaire, est une autre possibilité, mais pas très flexible. Un lien vers des URL avec des formulaires complètement en dehors de Wagtail peut être une solution appropriée pour se connecter / s'inscrire, mais n'est pas non plus idéal. Dans ce didacticiel, on va implémenter Wagtail Streamforms, qui nous fournira de nombreux champs prêts à l'emploi, tels que le texte sur une seule ligne et sur plusieurs lignes, la date, l'e-mail, la case à cocher, le fichier. On y ajoutera également un champ reCaptcha et créera une page de contact avec un formulaire de contact pour notre site. Il y a cependant une mise en garde que je devrais mentionner au début: un problème de compatibilité mineur avec Django 3.0, dont je parlerai vers la fin de cet article.
Installer avec:
pip3 install wagtailstreamforms
Ajoutez-le à requirements.txt
et ajoutez ce qui suit à INSTALLED_APPS
(wagtail.contrib.modeladmin
peut déjà être là):
'wagtail.contrib.modeladmin',
'wagtailstreamforms',
On peut maintenant créer un modèle pour une page de contact dans models.py
(sous-classé de TranslatablePage
si notre site est multilingue):
from wagtail.admin.edit_handlers import FieldPanel, StreamFieldPanel
from wagtail.core.fields import RichTextField, StreamField
from wagtail.core import blocks
from wagtailtrans.models import TranslatablePage
from wagtailstreamforms.blocks import WagtailFormBlock
class ContactPage(TranslatablePage):
intro = RichTextField(blank=True)
body = StreamField([
('paragraph', blocks.RichTextBlock()),
('form', WagtailFormBlock()),
])
content_panels = TranslatablePage.content_panels + [
FieldPanel('intro'),
StreamFieldPanel('body'),
]
Bien sûr, on peut ajouter plus de champs à la page si on le veut. On peut maintenant créer le modèle html, dans un fichier custom_form.html
:
<form{% if form.is_multipart %} enctype="multipart/form-data"{% endif %} action="{{ value.form_action }}" method="post" class="needs-validation" novalidate>
{{ form.media }}
{% csrf_token %}
{% for hidden in form.hidden_fields %}{{ hidden }}{% endfor %}
{% for field in form.visible_fields %}
<div class="form-group">
{% include "account/form_field.html" %}
</div>
{% endfor %}
<button type="submit" class="btn btn-outline-primary">{{ value.form.submit_button_text }}</button>
</form>
Il ressemble beaucoup au modèle dans la documentation, on vient d'inclure notre propre modèle form_field.html
joliment stylisé qu'on a utilisé dans les didacticiels précédents, et un bouton différent. Comme indiqué, on ajoute le formulaire personnalisé, avec celui par défaut, à nos paramètres:
WAGTAILSTREAMFORMS_FORM_TEMPLATES = (
('streamforms/form_block.html', _("Default Form Template")), # default
('cms/custom_form.html', _("Custom Form Template")),
)
On a encore besoin d'un modèle pour la classe de page de contact. Il s'agit essentiellement d'afficher simplement le corps de la classe de page de contact, qui est un StreamField. On va ajouter des messages de Wagtailstreamforms, s'il y en a; cela est décrit dans la documentation. Le code du modèle est alors:
{% extends 'account/base_card.html' %}
{% load i18n wagtailcore_tags %}
{% block card-header %}
<h3>{{ page.title }}</h3>
<p>{{ page.intro|richtext }}</p>
{% endblock %}
{% block card-body %}
{% if messages %}
{% for message in messages %}
<p{% if message.tags %} class="{{ message.tags }}"{% endif %}>{{ message }}</p>
{% endfor %}
{% endif %}
{% if page.body %}
{% include "streamfield.html" %}
{% endif %}
{% endblock %}
En principe, on a maintenant un générateur de formulaires qui fonctionne et on peut migrer la base de données. Cependant, on aimer ajouter quelques éléments. Tout d'abord, faisons en sorte que notre application envoie un mail à une adresse spécifique lorsqu'un formulaire est soumis via la page contact. Cela se fait avec un hook de soumission dans un fichier séparé wagtailstreamforms_hooks.py
, comme expliqué dans la documentation de Wagtail Streamforms; le code est littéralement écrit. Dans ce document, l'adresse de destination (à laquelle l'e-mail est envoyé) est fixée; il est plus agréable de le rendre configurable dans l'éditeur. Cela aussi est décrit dans la documentation, alors faisons-le d'abord. Dans models.py
, créez le modèle:
from wagtailstreamforms.models.abstract import AbstractFormSetting
class AdvancedFormSetting(AbstractFormSetting):
to_address = models.EmailField()
et dans votre fichier de paramètres, définissez un paramètre pour pointer vers cette classe:
WAGTAILSTREAMFORMS_ADVANCED_SETTINGS_MODEL = 'cms.AdvancedFormSetting'
Maintenant, on est prêt à créer un fichier wagtailstreamforms_hooks.py
et à coller le code à partir de la documentation là-dedans:
from django.conf import settings
from django.core.mail import EmailMessage
from django.template.defaultfilters import pluralize
from wagtailstreamforms.hooks import register
@register('process_form_submission')
def email_submission(instance, form):
""" Send an email with the submission. """
addresses = [instance.advanced_settings.to_address]
content = ['Please see below submission\n', ]
from_address = settings.DEFAULT_FROM_EMAIL
subject = 'New Form Submission : %s' % instance.title
# build up the email content
for field, value in form.cleaned_data.items():
if field in form.files:
count = len(form.files.getlist(field))
value = '{} file{}'.format(count, pluralize(count))
elif isinstance(value, list):
value = ', '.join(value)
content.append('{}: {}'.format(field, value))
content = '\n'.join(content)
# create the email message
email = EmailMessage(
subject=subject,
body=content,
from_email=from_address,
to=addresses
)
# attach any files submitted
for field in form.files:
for file in form.files.getlist(field):
file.seek(0)
email.attach(file.name, file.read(), file.content_type)
# finally send the email
email.send(fail_silently=True)
La seule chose qu'on a modifiée est l'adresse de destination, dans notre instance.advanced_settings.to_address
nouvellement créée.
Une dernière étape consiste à ajouter reCaptcha, qui est également bien documenté. On a d'abord besoin de clés reCaptcha pour avoir accès. Accédez à https://www.google.com/u/1/recaptcha/admin/create lorsque vous êtes connecté avec votre compte Google et enregistrez votre site; c'est assez simple. On utilisera reCaptcha v2, vérifiez ici pour les différentes versions. Cela vous donnera une clé publique et privée dont on aura besoin. Lorsque vous testez cela sur votre ordinateur local (dans mon cas, un Mac), vous pouvez obtenir une erreur [SSL: CERTIFICATE_VERIFY_FAILED]
; vérifiez ici pour une solution.
Ensuite, on doit installer reCaptcha. Il existe un certain nombre de packages pour cela, on s'en tiendra à celui qui est utilisé dans les documents de Wagtail Streamforms:
pip3 install django-recaptcha
Ajoutez-le à requirements.txt
et ajoutez captcha
à INSTALLED_APPS
. Mettez la clé publique et privée du développeur dans vos paramètres et activez noCaptcha:
# reCaptcha settings
RECAPTCHA_PUBLIC_KEY = '<your public reCaptcha key>'
RECAPTCHA_PRIVATE_KEY = '<your private reCaptcha key>'
# enable no captcha
NOCAPTCHA = True
Étant donné que vous souhaitez empêcher votre clé privée de se retrouver dans votre référentiel, vous souhaiterez peut-être la placer dans la partie non suivie de vos paramètres. Enfin, créez un fichier wagtailstreamforms_fields.py
et collez le code dans la documentation; c'est une copie littérale, donc je ne vais pas la répéter ici. Il contient la définition du champ reCaptcha et l'enregistre comme tel.
On est presque prêt, mais il y a un problème: Wagtail Streamforms n'est pas encore compatible avec Django 3.0. "Quoi?!", je vous entends penser, "et vous me dites ça maintenant?". Cela semble en fait pire qu'il ne l'est. Django 3.0 a supprimé l'argument context
de la méthode Field.from_db_value()
et Wagtail Streamforms l'attend toujours. Le problème a été identifié par l'équipe Wagtail Streamforms et une solution simple a été proposée: dans la méthode from_db_value
, changez l'argument context
en context=None
. Il n'a tout simplement pas été fusionné lors de la rédaction de cet article. Une possibilité de gérer cela serait de bifurquer le référentiel de Wagtail Streamforms, de faire le changement dans le fork et d'utiliser ce fork au lieu des wagtailstreamforms d'origine. Pour le développement, on utilisera la solution rapide et sale et fera le changement dans notre environnement local. Non recommandé pour la production! Surveillons de près la résolution de ce problème.
Dans cet esprit, continuons. Migrez la base de données si vous ne l'avez pas déjà fait et accédez à l'admin. Créez un formulaire avec tous les champs que vous aimez, puis créez une page de contact contenant ce formulaire. Cliquez sur avancé pour sélectionner la soumission par e-mail et/ou enregistrer la soumission du formulaire. Essayez-le: remplissez-le et envoyez-le, il devrait se retrouver dans votre boîte aux lettres.
Dans un site multilingue, on aimerait évidemment des formulaires dans différentes langues. Pour cela, il faut recréer la même forme dans l'autre langue; il n'y a aucun moyen (encore) de regrouper toutes les formes traduites en un seul ensemble. Tant que le nombre de formulaires est limité, ce n'est pas vraiment un problème. On peut alors simplement connecter le formulaire traduit à la page traduite respective.
Dans le cas où vous avez créé un menu de navigation, l'ajout de la page de contact est simple: allez simplement dans le menu dans admin et ajoutez le lien vers la page. Regardez la vidéo si vous souhaitez voir comment.
On en a fini avec les formulaires pour l'instant. Si vous êtes prêt à tester votre application, lisez plus.
Commentez cet article (connectez-vous d'abord ou confirmez par nom et email ci-dessous)